Skip to content

Commit

Permalink
Merge branch 'master' into upBNMay24
Browse files Browse the repository at this point in the history
  • Loading branch information
CedricGuillemet authored May 23, 2024
2 parents b90c341 + 197fe21 commit 391b6ad
Show file tree
Hide file tree
Showing 26 changed files with 20,247 additions and 0 deletions.
14 changes: 14 additions & 0 deletions Apps/BRNPlayground/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
*.binlog
*.hprof
*.zip
.DS_Store
.gradle/
.idea/
.vs/
.xcode.env
Pods/
build/
dist/
local.properties
msbuild.binlog
node_modules/
1 change: 1 addition & 0 deletions Apps/BRNPlayground/.watchmanconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
285 changes: 285 additions & 0 deletions Apps/BRNPlayground/App.tsx
Original file line number Diff line number Diff line change
@@ -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<ViewProps> = (props: ViewProps) => {
const defaultScale = 1;
const enableSnapshots = false;

const engine = useEngine();
const [toggleView, setToggleView] = useState(false);
const [camera, setCamera] = useState<Camera>();
const [rootNode, setRootNode] = useState<TransformNode>();
const [scene, setScene] = useState<Scene>();
const [xrSession, setXrSession] = useState<WebXRSessionManager>();
const [scale, setScale] = useState<number>(defaultScale);
const [snapshotData, setSnapshotData] = useState<string>();
const [engineViewCallbacks, setEngineViewCallbacks] =
useState<EngineViewCallbacks>();
const [trackingState, setTrackingState] = useState<WebXRTrackingState>();

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 (
<>
<View style={props.style}>
<Button
title="Toggle EngineView"
onPress={() => {
setToggleView(!toggleView);
}}
/>
<Button
title={xrSession ? "Stop XR" : "Start XR"}
onPress={onToggleXr}
/>
{!toggleView && (
<View style={{ flex: 1 }}>
{enableSnapshots && (
<View style={{ flex: 1 }}>
<Button title={"Take Snapshot"} onPress={onSnapshot} />
<Image style={{ flex: 1 }} source={{ uri: snapshotData }} />
</View>
)}
<EngineView
camera={camera}
onInitialized={onInitialized}
displayFrameRate={true}
antiAliasing={2}
/>
<Slider
style={{
position: "absolute",
minHeight: 50,
margin: 10,
left: 0,
right: 0,
bottom: 0,
}}
minimumValue={0.2}
maximumValue={2}
step={0.01}
value={defaultScale}
onValueChange={setScale}
/>
<Text style={{ color: "yellow", position: "absolute", margin: 3 }}>
{trackingStateToString(trackingState)}
</Text>
</View>
)}
{toggleView && (
<View
style={{ flex: 1, justifyContent: "center", alignItems: "center" }}
>
<Text style={{ fontSize: 24 }}>EngineView has been removed.</Text>
<Text style={{ fontSize: 12 }}>
Render loop stopped, but engine is still alive.
</Text>
</View>
)}
</View>
</>
);
};

const App = () => {
const [toggleScreen, setToggleScreen] = useState(false);

return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView style={{ flex: 1, backgroundColor: "white" }}>
{!toggleScreen && <EngineScreen style={{ flex: 1 }} />}
{toggleScreen && (
<View
style={{ flex: 1, justifyContent: "center", alignItems: "center" }}
>
<Text style={{ fontSize: 24 }}>EngineScreen has been removed.</Text>
<Text style={{ fontSize: 12 }}>
Engine has been disposed, and will be recreated.
</Text>
</View>
)}
<Button
title="Toggle EngineScreen"
onPress={() => {
setToggleScreen(!toggleScreen);
}}
/>
</SafeAreaView>
</>
);
};

export default App;
12 changes: 12 additions & 0 deletions Apps/BRNPlayground/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# BabylonReactNative Playground App

This is a new example app for BabylonReactNative, based on `react-native-test-app`.

It's still getting fully wired up as a replacement, so if you are seeing this message it means that it's not in its final form yet!

To run it (on an Android device):

1. `npm i`
2. `npm run android`

(assuming that you have your setup working for running [RN Android apps on device](https://reactnative.dev/docs/running-on-device?platform=android))
26 changes: 26 additions & 0 deletions Apps/BRNPlayground/android/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
buildscript {
def androidTestAppDir = "../node_modules/react-native-test-app/android"
apply(from: "${androidTestAppDir}/dependencies.gradle")

repositories {
mavenCentral()
google()
}

dependencies {
getReactNativeDependencies().each { dependency ->
classpath(dependency)
}
}
}

allprojects {
repositories {
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url("${rootDir}/../node_modules/react-native/android")
}
mavenCentral()
google()
}
}
49 changes: 49 additions & 0 deletions Apps/BRNPlayground/android/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Project-wide Gradle settings.

# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.

# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html

# Specifies the JVM arguments used for the Gradle Daemon. The setting is
# particularly useful for configuring JVM memory settings for build performance.
# This does not affect the JVM settings for the Gradle client VM.
# The default is `-Xmx512m -XX:MaxMetaspaceSize=256m`.
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

# When configured, Gradle will fork up to org.gradle.workers.max JVMs to execute
# projects in parallel. To learn more about parallel task execution, see the
# section on Gradle build performance:
# https://docs.gradle.org/current/userguide/performance.html#parallel_execution.
# Default is `false`.
#org.gradle.parallel=true

# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# Jetifier randomly fails on these libraries
android.jetifier.ignorelist=hermes-android

# Use this property to specify which architecture you want to build.
# You can also override it from the CLI using
# ./gradlew <task> -PreactNativeArchitectures=x86_64
reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64

# Use this property to enable support to the new architecture.
# This will allow you to use TurboModules and the Fabric render in
# your application. You should enable this flag either if you want
# to write custom TurboModules/Fabric components OR use libraries that
# are providing them.
# Note that this is incompatible with web debugging.
#newArchEnabled=true

# Uncomment the line below if building react-native from source
#ANDROID_NDK_VERSION=26.1.10909125

# Version of Kotlin to build against.
#KOTLIN_VERSION=1.8.22
Binary file not shown.
Loading

0 comments on commit 391b6ad

Please sign in to comment.