UNPKG

@osobh/reactar

Version:

AR Library for React Native and Expo

195 lines 8.54 kB
"use strict"; // src/core/ARRenderer.tsx var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); const react_1 = __importStar(require("react")); const react_native_1 = require("react-native"); const GL = __importStar(require("expo-gl")); const expo_camera_1 = require("expo-camera"); const expo_three_1 = require("expo-three"); const PlaneDetection_1 = require("./PlaneDetection"); const ARRenderer = () => { const requestRef = (0, react_1.useRef)(null); const glViewRef = (0, react_1.useRef)(null); const cameraRef = (0, react_1.useRef)(null); const planeDetection = (0, react_1.useRef)(new PlaneDetection_1.PlaneDetection()); const [snapshot, setSnapshot] = (0, react_1.useState)(); const [zoom, setZoom] = (0, react_1.useState)(0); const [cameraType, setCameraType] = (0, react_1.useState)(expo_camera_1.CameraType.back); const [cameraTexture, setCameraTexture] = (0, react_1.useState)(null); /** * This function is called once the GLView context is created. * It sets up a three.js renderer, scene, camera, and a sample cube. */ const takeSnapshot = async () => { if (glViewRef.current) { const snapshot = await glViewRef.current.takeSnapshotAsync({ format: 'png', }); setSnapshot(snapshot); } }; const createCameraTexture = async (gl) => { if (glViewRef.current && cameraRef.current) { const texture = await glViewRef.current.createCameraTextureAsync(cameraRef.current); setCameraTexture(texture); return texture; } return null; }; const onContextCreate = async (gl) => { // Create camera texture const texture = await createCameraTexture(gl); // Create a three.js renderer using Expo's GL context const renderer = new expo_three_1.Renderer({ gl }); const { drawingBufferWidth: width, drawingBufferHeight: height } = gl; renderer.setSize(width, height); renderer.setClearColor(0xffffff, 0); // Create a new three.js scene const scene = new expo_three_1.THREE.Scene(); // Initialize plane detection with Three.js scene and camera planeDetection.current.setScene(scene); // Move camera setup before using it const camera = new expo_three_1.THREE.PerspectiveCamera(75, width / height, 0.1, 1000); camera.position.z = 5; planeDetection.current.setCamera(camera); // Create a simple cube geometry with a basic material const geometry = new expo_three_1.THREE.BoxGeometry(1, 1, 1); const material = new expo_three_1.THREE.MeshBasicMaterial({ color: 'tomato' }); const cube = new expo_three_1.THREE.Mesh(geometry, material); scene.add(cube); // Animation loop: rotates the cube and renders the scene const animate = () => { requestRef.current = requestAnimationFrame(animate); // Update cube rotation for basic animation cube.rotation.x += 0.02; cube.rotation.y += 0.02; // Detect planes // Add state for detected planes const [detectedPlanes, setDetectedPlanes] = (0, react_1.useState)([]); // Handle plane detection asynchronously planeDetection.current.detectPlanes() .then(planes => { setDetectedPlanes(planes); }) .catch(error => { console.error('Error detecting planes:', error); }); // Render the scene using the camera renderer.render(scene, camera); // Notify the GL context that the frame is complete if (gl.endFrameEXP) { gl.endFrameEXP(); } }; // Start the animation loop animate(); }; // Clean up the animation loop when the component is unmounted (0, react_1.useEffect)(() => { return () => { if (requestRef.current) { cancelAnimationFrame(requestRef.current); } }; }, []); const toggleCameraType = () => { setCameraType(current => current === expo_camera_1.CameraType.back ? expo_camera_1.CameraType.front : expo_camera_1.CameraType.back); }; const zoomIn = () => { setZoom(current => Math.min(current + 0.1, 1)); }; const zoomOut = () => { setZoom(current => Math.max(current - 0.1, 0)); }; return (react_1.default.createElement(react_native_1.View, { style: styles.container }, react_1.default.createElement(expo_camera_1.Camera, { ref: cameraRef, style: react_native_1.StyleSheet.absoluteFill, type: cameraType, zoom: zoom }), react_1.default.createElement(GL.GLView, { style: react_native_1.StyleSheet.absoluteFill, onContextCreate: onContextCreate, ref: glViewRef }), snapshot && (react_1.default.createElement(react_native_1.View, { style: styles.snapshot }, react_1.default.createElement(react_native_1.Image, { style: [styles.flex, { aspectRatio: snapshot.width / snapshot.height }], source: snapshot }))), react_1.default.createElement(react_native_1.View, { style: styles.controls }, react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.controlButton, onPress: toggleCameraType }, react_1.default.createElement(react_native_1.Text, null, "Flip")), react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.controlButton, onPress: zoomIn }, react_1.default.createElement(react_native_1.Text, null, "Zoom In")), react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.controlButton, onPress: zoomOut }, react_1.default.createElement(react_native_1.Text, null, "Zoom Out")), react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.controlButton, onPress: takeSnapshot }, react_1.default.createElement(react_native_1.Text, null, "Snapshot"))))); }; const styles = react_native_1.StyleSheet.create({ container: { flex: 1, }, glView: { flex: 1, }, flex: { flex: 1, }, snapshot: { height: 100, margin: 10, borderWidth: react_native_1.StyleSheet.hairlineWidth, borderColor: 'black', backgroundColor: '#248e80', position: 'absolute', left: 0, bottom: 0, shadowColor: 'black', shadowOpacity: 0.3, shadowRadius: 5, shadowOffset: { width: 0, height: 0 }, }, controls: { position: 'absolute', bottom: 0, left: 0, right: 0, flexDirection: 'row', justifyContent: 'space-around', padding: 10, }, controlButton: { paddingVertical: 10, paddingHorizontal: 15, backgroundColor: 'white', borderWidth: react_native_1.StyleSheet.hairlineWidth, borderColor: 'black', borderRadius: 5, }, }); exports.default = ARRenderer; //# sourceMappingURL=ARRenderer.js.map