From 197fe219e678688bc9a3ec9918c4fbcef350de05 Mon Sep 17 00:00:00 2001 From: Lorenzo Sciandra Date: Thu, 23 May 2024 09:01:30 +0100 Subject: [PATCH] feat(test app): add new RNTA-based test app (#641) * baseline: adding RNTA vanilla, it works * wire in the babylon stuff * a couple of temp files * minor cleanup, bump to latest 73 and RNTA * add a quick readme * Update Apps/BRNPlayground/macos/Podfile Co-authored-by: Tommy Nguyen <4123478+tido64@users.noreply.github.com> * Update Apps/BRNPlayground/postinstall.js Co-authored-by: Tommy Nguyen <4123478+tido64@users.noreply.github.com> * Update Apps/BRNPlayground/.gitignore Co-authored-by: Tommy Nguyen <4123478+tido64@users.noreply.github.com> * get CMake to build * add xcworkspace * bump to latest RN and RNTA --------- Co-authored-by: Tommy Nguyen <4123478+tido64@users.noreply.github.com> --- Apps/BRNPlayground/.gitignore | 14 + Apps/BRNPlayground/.watchmanconfig | 1 + Apps/BRNPlayground/App.tsx | 285 + Apps/BRNPlayground/README.md | 12 + Apps/BRNPlayground/android/build.gradle | 26 + Apps/BRNPlayground/android/gradle.properties | 49 + .../android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 63721 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + Apps/BRNPlayground/android/gradlew | 249 + Apps/BRNPlayground/android/gradlew.bat | 92 + Apps/BRNPlayground/android/settings.gradle | 12 + Apps/BRNPlayground/app.json | 28 + Apps/BRNPlayground/babel.config.js | 3 + Apps/BRNPlayground/index.js | 9 + .../contents.xcworkspacedata | 13 + Apps/BRNPlayground/ios/Podfile | 5 + Apps/BRNPlayground/ios/Podfile.lock | 1266 ++ Apps/BRNPlayground/macos/Podfile | 9 + Apps/BRNPlayground/macos/Podfile.lock | 1247 ++ Apps/BRNPlayground/metro.config.js | 18 + Apps/BRNPlayground/package-lock.json | 16748 ++++++++++++++++ Apps/BRNPlayground/package.json | 55 + Apps/BRNPlayground/postinstall.js | 40 + Apps/BRNPlayground/react-native.config.js | 23 + Apps/BRNPlayground/windows/.gitignore | 33 + .../ios/CMakeLists.txt | 3 + 26 files changed, 20247 insertions(+) create mode 100644 Apps/BRNPlayground/.gitignore create mode 100644 Apps/BRNPlayground/.watchmanconfig create mode 100644 Apps/BRNPlayground/App.tsx create mode 100644 Apps/BRNPlayground/README.md create mode 100644 Apps/BRNPlayground/android/build.gradle create mode 100644 Apps/BRNPlayground/android/gradle.properties create mode 100644 Apps/BRNPlayground/android/gradle/wrapper/gradle-wrapper.jar create mode 100644 Apps/BRNPlayground/android/gradle/wrapper/gradle-wrapper.properties create mode 100755 Apps/BRNPlayground/android/gradlew create mode 100644 Apps/BRNPlayground/android/gradlew.bat create mode 100644 Apps/BRNPlayground/android/settings.gradle create mode 100644 Apps/BRNPlayground/app.json create mode 100644 Apps/BRNPlayground/babel.config.js create mode 100644 Apps/BRNPlayground/index.js create mode 100644 Apps/BRNPlayground/ios/BRNPlayground.xcworkspace/contents.xcworkspacedata create mode 100644 Apps/BRNPlayground/ios/Podfile create mode 100644 Apps/BRNPlayground/ios/Podfile.lock create mode 100644 Apps/BRNPlayground/macos/Podfile create mode 100644 Apps/BRNPlayground/macos/Podfile.lock create mode 100644 Apps/BRNPlayground/metro.config.js create mode 100644 Apps/BRNPlayground/package-lock.json create mode 100644 Apps/BRNPlayground/package.json create mode 100644 Apps/BRNPlayground/postinstall.js create mode 100644 Apps/BRNPlayground/react-native.config.js create mode 100644 Apps/BRNPlayground/windows/.gitignore diff --git a/Apps/BRNPlayground/.gitignore b/Apps/BRNPlayground/.gitignore new file mode 100644 index 000000000..5fbd50620 --- /dev/null +++ b/Apps/BRNPlayground/.gitignore @@ -0,0 +1,14 @@ +*.binlog +*.hprof +*.zip +.DS_Store +.gradle/ +.idea/ +.vs/ +.xcode.env +Pods/ +build/ +dist/ +local.properties +msbuild.binlog +node_modules/ diff --git a/Apps/BRNPlayground/.watchmanconfig b/Apps/BRNPlayground/.watchmanconfig new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/Apps/BRNPlayground/.watchmanconfig @@ -0,0 +1 @@ +{} diff --git a/Apps/BRNPlayground/App.tsx b/Apps/BRNPlayground/App.tsx new file mode 100644 index 000000000..bbd4798b0 --- /dev/null +++ b/Apps/BRNPlayground/App.tsx @@ -0,0 +1,285 @@ +/** + * Generated with the TypeScript template + * https://github.com/react-native-community/react-native-template-typescript + * + * @format + */ + +import React, { + useState, + FunctionComponent, + useEffect, + useCallback, +} from "react"; +import { + SafeAreaView, + StatusBar, + Button, + View, + Text, + ViewProps, + Image, +} from "react-native"; + +import { + EngineView, + useEngine, + EngineViewCallbacks, +} from "@babylonjs/react-native"; +import { + Scene, + Vector3, + ArcRotateCamera, + Camera, + WebXRSessionManager, + SceneLoader, + TransformNode, + DeviceSourceManager, + DeviceType, + PointerInput, + WebXRTrackingState, + IMouseEvent, +} from "@babylonjs/core"; +import "@babylonjs/loaders"; +import Slider from "@react-native-community/slider"; + +const EngineScreen: FunctionComponent = (props: ViewProps) => { + const defaultScale = 1; + const enableSnapshots = false; + + const engine = useEngine(); + const [toggleView, setToggleView] = useState(false); + const [camera, setCamera] = useState(); + const [rootNode, setRootNode] = useState(); + const [scene, setScene] = useState(); + const [xrSession, setXrSession] = useState(); + const [scale, setScale] = useState(defaultScale); + const [snapshotData, setSnapshotData] = useState(); + const [engineViewCallbacks, setEngineViewCallbacks] = + useState(); + const [trackingState, setTrackingState] = useState(); + + useEffect(() => { + if (engine) { + const scene = new Scene(engine); + setScene(scene); + scene.createDefaultCamera(true); + (scene.activeCamera as ArcRotateCamera).beta -= Math.PI / 8; + setCamera(scene.activeCamera!); + scene.createDefaultLight(true); + const rootNode = new TransformNode("Root Container", scene); + setRootNode(rootNode); + + const deviceSourceManager = new DeviceSourceManager(engine); + const handlePointerInput = (event: IMouseEvent) => { + if (event.inputIndex === PointerInput.Move && event.movementX) { + rootNode.rotate(Vector3.Down(), event.movementX * 0.005); + } + }; + + deviceSourceManager.onDeviceConnectedObservable.add((device) => { + if (device.deviceType === DeviceType.Touch) { + const touch = deviceSourceManager.getDeviceSource( + device.deviceType, + device.deviceSlot + )!; + touch.onInputChangedObservable.add((touchEvent) => { + handlePointerInput(touchEvent); + }); + } else if (device.deviceType === DeviceType.Mouse) { + const mouse = deviceSourceManager.getDeviceSource( + device.deviceType, + device.deviceSlot + )!; + mouse.onInputChangedObservable.add((mouseEvent) => { + if (mouse.getInput(PointerInput.LeftClick)) { + handlePointerInput(mouseEvent); + } + }); + } + }); + + const transformContainer = new TransformNode( + "Transform Container", + scene + ); + transformContainer.parent = rootNode; + transformContainer.scaling.scaleInPlace(0.2); + transformContainer.position.y -= 0.2; + + scene.beforeRender = function () { + transformContainer.rotate( + Vector3.Up(), + 0.005 * scene.getAnimationRatio() + ); + }; + + SceneLoader.ImportMeshAsync( + "", + "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/BoxAnimated/glTF-Binary/BoxAnimated.glb" + ).then((result) => { + const mesh = result.meshes[0]; + mesh.parent = transformContainer; + }); + } + }, [engine]); + + useEffect(() => { + if (rootNode) { + rootNode.scaling = new Vector3(scale, scale, scale); + } + }, [rootNode, scale]); + + const trackingStateToString = ( + trackingState: WebXRTrackingState | undefined + ): string => { + return trackingState === undefined ? "" : WebXRTrackingState[trackingState]; + }; + + const onToggleXr = useCallback(() => { + (async () => { + if (xrSession) { + await xrSession.exitXRAsync(); + } else { + if (rootNode !== undefined && scene !== undefined) { + const xr = await scene.createDefaultXRExperienceAsync({ + disableDefaultUI: true, + disableTeleportation: true, + }); + const session = await xr.baseExperience.enterXRAsync( + "immersive-ar", + "unbounded", + xr.renderTarget + ); + setXrSession(session); + session.onXRSessionEnded.add(() => { + setXrSession(undefined); + setTrackingState(undefined); + }); + + setTrackingState(xr.baseExperience.camera.trackingState); + xr.baseExperience.camera.onTrackingStateChanged.add( + (newTrackingState) => { + setTrackingState(newTrackingState); + } + ); + + // TODO: Figure out why getFrontPosition stopped working + //box.position = (scene.activeCamera as TargetCamera).getFrontPosition(2); + const cameraRay = scene.activeCamera!.getForwardRay(1); + rootNode.position = cameraRay.origin.add( + cameraRay.direction.scale(cameraRay.length) + ); + rootNode.rotate(Vector3.Up(), 3.14159); + } + } + })(); + }, [rootNode, scene, xrSession]); + + const onInitialized = useCallback( + async (engineViewCallbacks: EngineViewCallbacks) => { + setEngineViewCallbacks(engineViewCallbacks); + }, + [engine] + ); + + const onSnapshot = useCallback(async () => { + if (engineViewCallbacks) { + setSnapshotData( + "data:image/jpeg;base64," + (await engineViewCallbacks.takeSnapshot()) + ); + } + }, [engineViewCallbacks]); + + return ( + <> + +