@babylonjs/react-native 0.4.0-alpha.7 → 0.64.0-alpha.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BabylonModule.d.ts +2 -0
- package/{BabylonModule.ts → BabylonModule.js} +9 -12
- package/BabylonModule.js.map +1 -0
- package/EngineHook.d.ts +3 -0
- package/EngineHook.js +179 -0
- package/EngineHook.js.map +1 -0
- package/EngineView.d.ts +13 -0
- package/EngineView.js +118 -0
- package/EngineView.js.map +1 -0
- package/FontFace.d.ts +12 -0
- package/FontFace.js +35 -0
- package/FontFace.js.map +1 -0
- package/NativeCapture.d.ts +14 -0
- package/NativeCapture.js +14 -0
- package/NativeCapture.js.map +1 -0
- package/README.md +8 -8
- package/ReactNativeEngine.d.ts +7 -0
- package/ReactNativeEngine.js +33 -0
- package/ReactNativeEngine.js.map +1 -0
- package/VersionValidation.d.ts +1 -0
- package/{VersionValidation.ts → VersionValidation.js} +3 -3
- package/VersionValidation.js.map +1 -0
- package/android/build.gradle +13 -1
- package/android/include/IXrContextARCore.h +10 -0
- package/android/src/main/java/com/babylonreactnative/BabylonModule.java +6 -4
- package/android/src/main/java/com/babylonreactnative/BabylonNativeInterop.java +20 -6
- package/android/src/main/java/com/babylonreactnative/EngineView.java +151 -8
- package/android/src/main/java/com/babylonreactnative/EngineViewManager.java +8 -0
- package/android/src/main/jniLibs/arm64-v8a/libBabylonNative.so +0 -0
- package/android/src/main/jniLibs/arm64-v8a/libturbomodulejsijni.so +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libBabylonNative.so +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libturbomodulejsijni.so +0 -0
- package/android/src/main/jniLibs/x86/libBabylonNative.so +0 -0
- package/android/src/main/jniLibs/x86/libturbomodulejsijni.so +0 -0
- package/index.d.ts +4 -0
- package/index.js +5 -0
- package/index.js.map +1 -0
- package/ios/BabylonModule.mm +7 -0
- package/ios/BabylonNativeInterop.h +4 -0
- package/ios/BabylonNativeInterop.mm +37 -14
- package/ios/EngineViewManager.mm +41 -3
- package/ios/ReactNativeBabylon.xcodeproj/project.pbxproj +7609 -9451
- package/ios/include/IXrContextARKit.h +10 -0
- package/ios/libs/libBabylonNative.a +0 -0
- package/ios/libs/libCanvas.a +0 -0
- package/ios/libs/libGenericCodeGen.a +0 -0
- package/ios/libs/libGraphics.a +0 -0
- package/ios/libs/libJsRuntime.a +0 -0
- package/ios/libs/libMachineIndependent.a +0 -0
- package/ios/libs/libNativeCapture.a +0 -0
- package/ios/libs/libNativeEngine.a +0 -0
- package/ios/libs/libNativeInput.a +0 -0
- package/ios/libs/libNativeOptimizations.a +0 -0
- package/ios/libs/libNativeTracing.a +0 -0
- package/ios/libs/libNativeXr.a +0 -0
- package/ios/libs/libOGLCompiler.a +0 -0
- package/ios/libs/libOSDependent.a +0 -0
- package/ios/libs/libSPIRV.a +0 -0
- package/ios/libs/libUrlLib.a +0 -0
- package/ios/libs/libWindow.a +0 -0
- package/ios/libs/libXMLHttpRequest.a +0 -0
- package/ios/libs/libastc-codec.a +0 -0
- package/ios/libs/libastc.a +0 -0
- package/ios/libs/libbgfx.a +0 -0
- package/ios/libs/libbimg.a +0 -0
- package/ios/libs/libbx.a +0 -0
- package/ios/libs/libglslang.a +0 -0
- package/ios/libs/libnapi.a +0 -0
- package/ios/libs/libspirv-cross-core.a +0 -0
- package/ios/libs/libspirv-cross-glsl.a +0 -0
- package/ios/libs/libspirv-cross-msl.a +0 -0
- package/ios/libs/libtinyexr.a +0 -0
- package/ios/libs/libxr.a +0 -0
- package/package.json +53 -52
- package/shared/BabylonNative.h +30 -3
- package/shared/XrAnchorHelper.h +229 -0
- package/shared/XrContextHelper.h +179 -0
- package/EngineHook.ts +0 -103
- package/EngineView.tsx +0 -156
- package/ReactNativeEngine.ts +0 -69
- package/index.ts +0 -2
- package/ios/libs/libspirv-cross-hlsl.a +0 -0
package/EngineHook.ts
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react';
|
|
2
|
-
import { Platform } from 'react-native';
|
|
3
|
-
import { PERMISSIONS, check, request } from 'react-native-permissions';
|
|
4
|
-
import { Engine, WebXRSessionManager, WebXRExperienceHelper, Color3 } from '@babylonjs/core';
|
|
5
|
-
import { ReactNativeEngine } from './ReactNativeEngine';
|
|
6
|
-
import './VersionValidation';
|
|
7
|
-
import * as base64 from 'base-64';
|
|
8
|
-
|
|
9
|
-
// These are errors that are normally thrown by WebXR's requestSession, so we should throw the same errors under similar circumstances so app code can be written the same for browser or native.
|
|
10
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/XRSystem/requestSession
|
|
11
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/DOMException#Error_names
|
|
12
|
-
enum DOMError {
|
|
13
|
-
NotSupportedError = 9,
|
|
14
|
-
InvalidStateError = 11,
|
|
15
|
-
SecurityError = 18,
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
class DOMException {
|
|
19
|
-
public constructor(private readonly error: DOMError) { }
|
|
20
|
-
get code(): number { return this.error; }
|
|
21
|
-
get name(): string { return DOMError[this.error]; }
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Override the WebXRSessionManager.initializeSessionAsync to insert a camera permissions request. It would be cleaner to do this directly in the native XR implementation, but there are a couple problems with that:
|
|
25
|
-
// 1. React Native does not provide a way to hook into the permissions request result (at least on Android).
|
|
26
|
-
// 2. If it is done on the native side, then we need one implementation per platform.
|
|
27
|
-
{
|
|
28
|
-
const originalInitializeSessionAsync: (...args: any[]) => Promise<any> = WebXRSessionManager.prototype.initializeSessionAsync;
|
|
29
|
-
WebXRSessionManager.prototype.initializeSessionAsync = async function (...args: any[]): Promise<any> {
|
|
30
|
-
if (Platform.OS === "windows")
|
|
31
|
-
{
|
|
32
|
-
// Launching into immersive mode on Windows HMDs doesn't require a runtime permission check.
|
|
33
|
-
// The Spatial Perception capability should be enabled in the project's Package.appxmanifest.
|
|
34
|
-
return originalInitializeSessionAsync.apply(this, args);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const cameraPermission = Platform.select({
|
|
38
|
-
android: PERMISSIONS.ANDROID.CAMERA,
|
|
39
|
-
ios: PERMISSIONS.IOS.CAMERA,
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
// Only Android, iOS and Windows are supported.
|
|
43
|
-
if (cameraPermission === undefined) {
|
|
44
|
-
throw new DOMException(DOMError.NotSupportedError);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// If the permission has not been granted yet, but also not been blocked, then request permission.
|
|
48
|
-
let permissionStatus = await check(cameraPermission);
|
|
49
|
-
if (permissionStatus == "denied")
|
|
50
|
-
{
|
|
51
|
-
permissionStatus = await request(cameraPermission);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// If the permission has still not been granted, then throw an appropriate exception, otherwise continue with the actual XR session initialization.
|
|
55
|
-
switch(permissionStatus) {
|
|
56
|
-
case "unavailable":
|
|
57
|
-
throw new DOMException(DOMError.NotSupportedError);
|
|
58
|
-
case "denied":
|
|
59
|
-
case "blocked":
|
|
60
|
-
throw new DOMException(DOMError.SecurityError);
|
|
61
|
-
case "granted":
|
|
62
|
-
return originalInitializeSessionAsync.apply(this, args);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (Platform.OS == "windows") {
|
|
68
|
-
const originalEnterXRAsync: (...args: any[]) => Promise<any> = WebXRExperienceHelper.prototype.enterXRAsync;
|
|
69
|
-
WebXRExperienceHelper.prototype.enterXRAsync = async function (...args: any[]): Promise<any> {
|
|
70
|
-
// TODO: https://github.com/BabylonJS/BabylonNative/issues/577
|
|
71
|
-
// Windows HMDs require different rendering behaviors than default xr rendering for mobile devices
|
|
72
|
-
await originalEnterXRAsync.apply(this, args);
|
|
73
|
-
this.scene.clearColor = Color3.Black().toColor4();
|
|
74
|
-
this.scene.autoClear = true;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Babylon Native includes a native atob polyfill, but it relies JSI to deal with the strings, and JSI has a bug where it assumes strings are null terminated, and a base 64 string can contain one of these.
|
|
79
|
-
// So for now, provide a JavaScript based atob polyfill.
|
|
80
|
-
declare const global: any;
|
|
81
|
-
global.atob = base64.decode;
|
|
82
|
-
|
|
83
|
-
export function useEngine(): Engine | undefined {
|
|
84
|
-
const [engine, setEngine] = useState<Engine>();
|
|
85
|
-
|
|
86
|
-
useEffect(() => {
|
|
87
|
-
const abortController = new AbortController();
|
|
88
|
-
let engine: ReactNativeEngine | undefined = undefined;
|
|
89
|
-
|
|
90
|
-
(async () => {
|
|
91
|
-
setEngine(engine = await ReactNativeEngine.tryCreateAsync(abortController.signal) ?? undefined);
|
|
92
|
-
})();
|
|
93
|
-
|
|
94
|
-
return () => {
|
|
95
|
-
abortController.abort();
|
|
96
|
-
// NOTE: Do not use setEngine with a callback to dispose the engine instance as that callback does not get called during component unmount when compiled in release.
|
|
97
|
-
engine?.dispose();
|
|
98
|
-
setEngine(undefined);
|
|
99
|
-
};
|
|
100
|
-
}, []);
|
|
101
|
-
|
|
102
|
-
return engine;
|
|
103
|
-
}
|
package/EngineView.tsx
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import React, { Component, FunctionComponent, SyntheticEvent, useCallback, useEffect, useState, useRef } from 'react';
|
|
2
|
-
import { requireNativeComponent, ViewProps, AppState, AppStateStatus, View, Text, findNodeHandle, UIManager } from 'react-native';
|
|
3
|
-
import { Camera } from '@babylonjs/core';
|
|
4
|
-
import { ensureInitialized } from './BabylonModule';
|
|
5
|
-
import { ReactNativeEngine } from './ReactNativeEngine';
|
|
6
|
-
|
|
7
|
-
declare const global: any;
|
|
8
|
-
|
|
9
|
-
interface NativeEngineViewProps extends ViewProps {
|
|
10
|
-
onSnapshotDataReturned: (event: SyntheticEvent) => void;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const NativeEngineView: {
|
|
14
|
-
prototype: Component<NativeEngineViewProps>;
|
|
15
|
-
new(props: Readonly<NativeEngineViewProps>): Component<NativeEngineViewProps>;
|
|
16
|
-
} = global['EngineView'] || (global['EngineView'] = requireNativeComponent('EngineView'));
|
|
17
|
-
|
|
18
|
-
export interface EngineViewProps extends ViewProps {
|
|
19
|
-
camera?: Camera;
|
|
20
|
-
displayFrameRate?: boolean;
|
|
21
|
-
onInitialized?: (view: EngineViewCallbacks) => void;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface EngineViewCallbacks {
|
|
25
|
-
takeSnapshot: () => Promise<string>;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export const EngineView: FunctionComponent<EngineViewProps> = (props: EngineViewProps) => {
|
|
29
|
-
const [initialized, setInitialized] = useState<boolean>();
|
|
30
|
-
const [appState, setAppState] = useState(AppState.currentState);
|
|
31
|
-
const [fps, setFps] = useState<number>();
|
|
32
|
-
const engineViewRef = useRef<Component<NativeEngineViewProps>>(null);
|
|
33
|
-
const snapshotPromise = useRef<{ promise: Promise<string>, resolve: (data: string) => void }>();
|
|
34
|
-
|
|
35
|
-
useEffect(() => {
|
|
36
|
-
(async () => {
|
|
37
|
-
setInitialized(await ensureInitialized());
|
|
38
|
-
})();
|
|
39
|
-
}, []);
|
|
40
|
-
|
|
41
|
-
useEffect(() => {
|
|
42
|
-
const onAppStateChanged = (appState: AppStateStatus) => {
|
|
43
|
-
setAppState(appState);
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
AppState.addEventListener("change", onAppStateChanged);
|
|
47
|
-
|
|
48
|
-
return () => {
|
|
49
|
-
AppState.removeEventListener("change", onAppStateChanged);
|
|
50
|
-
}
|
|
51
|
-
}, []);
|
|
52
|
-
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
if (props.camera && appState === "active") {
|
|
55
|
-
const engine = props.camera.getScene().getEngine() as ReactNativeEngine;
|
|
56
|
-
|
|
57
|
-
if (!engine.isDisposed) {
|
|
58
|
-
engine.runRenderLoop(() => {
|
|
59
|
-
for (let scene of engine.scenes) {
|
|
60
|
-
scene.render();
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
return () => {
|
|
65
|
-
if (!engine.isDisposed) {
|
|
66
|
-
engine.stopRenderLoop();
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return undefined;
|
|
73
|
-
}, [props.camera, appState]);
|
|
74
|
-
|
|
75
|
-
useEffect(() => {
|
|
76
|
-
if (props.camera && (props.displayFrameRate ?? __DEV__)) {
|
|
77
|
-
const engine = props.camera.getScene().getEngine() as ReactNativeEngine;
|
|
78
|
-
|
|
79
|
-
if (!engine.isDisposed) {
|
|
80
|
-
setFps(engine.getFps());
|
|
81
|
-
const timerHandle = setInterval(() => {
|
|
82
|
-
setFps(engine.getFps());
|
|
83
|
-
}, 1000);
|
|
84
|
-
|
|
85
|
-
return () => {
|
|
86
|
-
clearInterval(timerHandle);
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
setFps(undefined);
|
|
92
|
-
return undefined;
|
|
93
|
-
}, [props.camera, props.displayFrameRate]);
|
|
94
|
-
|
|
95
|
-
// Call onInitialized if provided, and include the callback for takeSnapshot.
|
|
96
|
-
useEffect(() => {
|
|
97
|
-
if (props.onInitialized) {
|
|
98
|
-
props.onInitialized({
|
|
99
|
-
takeSnapshot: (): Promise<string> => {
|
|
100
|
-
if (!snapshotPromise.current) {
|
|
101
|
-
let resolveFunction: ((data: string) => void) | undefined;
|
|
102
|
-
const promise = new Promise<string>((resolutionFunc) => {
|
|
103
|
-
resolveFunction = resolutionFunc;
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
// Resolution functions should always be initialized.
|
|
107
|
-
if (resolveFunction) {
|
|
108
|
-
snapshotPromise.current = { promise: promise, resolve: resolveFunction };
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
throw new Error("Resolution functions not initialized after snapshot promise creation.");
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
UIManager.dispatchViewManagerCommand(
|
|
115
|
-
findNodeHandle(engineViewRef.current),
|
|
116
|
-
"takeSnapshot",
|
|
117
|
-
[]);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return snapshotPromise.current.promise;
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
}, [props.onInitialized]);
|
|
125
|
-
|
|
126
|
-
// Handle snapshot data returned.
|
|
127
|
-
const snapshotDataReturnedHandler = useCallback((event: SyntheticEvent) => {
|
|
128
|
-
// The nativeEvent is a DOMEvent which doesn't have a typescript definition. Cast it to an Event object with a data property.
|
|
129
|
-
const { data } = event.nativeEvent as Event & { data: string };
|
|
130
|
-
if (snapshotPromise.current) {
|
|
131
|
-
snapshotPromise.current.resolve(data);
|
|
132
|
-
snapshotPromise.current = undefined;
|
|
133
|
-
}
|
|
134
|
-
}, []);
|
|
135
|
-
|
|
136
|
-
if (initialized !== false) {
|
|
137
|
-
return (
|
|
138
|
-
<View style={[props.style, { overflow: "hidden" }]}>
|
|
139
|
-
{ initialized && <NativeEngineView ref={engineViewRef} style={{ flex: 1 }} onSnapshotDataReturned={snapshotDataReturnedHandler} /> }
|
|
140
|
-
{ fps && <Text style={{ color: 'yellow', position: 'absolute', margin: 10, right: 0, top: 0 }}>FPS: {Math.round(fps)}</Text> }
|
|
141
|
-
</View>
|
|
142
|
-
);
|
|
143
|
-
} else {
|
|
144
|
-
const message = "Could not initialize Babylon Native.";
|
|
145
|
-
if (!__DEV__) {
|
|
146
|
-
throw new Error(message);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
return (
|
|
150
|
-
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
|
151
|
-
<Text style={{ fontSize: 24 }}>{message}</Text>
|
|
152
|
-
<Text style={{ fontSize: 12 }}>React Native remote debugging does not work with Babylon Native.</Text>
|
|
153
|
-
</View>
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
}
|
package/ReactNativeEngine.ts
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { ensureInitialized } from './BabylonModule';
|
|
2
|
-
import { NativeEngine } from '@babylonjs/core';
|
|
3
|
-
|
|
4
|
-
// This global object is owned by Babylon Native.
|
|
5
|
-
declare const _native: {
|
|
6
|
-
whenGraphicsReady: () => Promise<void>;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
// This JSI-based global object is owned by Babylon React Native.
|
|
10
|
-
// This will likely be converted to a TurboModule when they are fully supported.
|
|
11
|
-
declare const BabylonNative: {
|
|
12
|
-
readonly initializationPromise: Promise<void>;
|
|
13
|
-
setEngineInstance: (engine: NativeEngine | null) => void;
|
|
14
|
-
reset: () => void;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export class ReactNativeEngine extends NativeEngine {
|
|
18
|
-
private _isDisposed = false;
|
|
19
|
-
|
|
20
|
-
private constructor() {
|
|
21
|
-
super();
|
|
22
|
-
BabylonNative.setEngineInstance(this);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
public static async tryCreateAsync(abortSignal: AbortSignal): Promise<ReactNativeEngine | null> {
|
|
26
|
-
if (!await ensureInitialized() || abortSignal.aborted) {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// This waits Graphics/NativeEngine to be created (which in turn makes the whenGraphicsReady available).
|
|
31
|
-
await BabylonNative.initializationPromise;
|
|
32
|
-
|
|
33
|
-
// Check for cancellation.
|
|
34
|
-
if (abortSignal.aborted) {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// This waits for the Graphics system to be up and running.
|
|
39
|
-
await _native.whenGraphicsReady();
|
|
40
|
-
|
|
41
|
-
// Check for cancellation.
|
|
42
|
-
if (abortSignal.aborted) {
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return new ReactNativeEngine();
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
public get isDisposed() {
|
|
50
|
-
return this._isDisposed;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
public dispose(): void {
|
|
54
|
-
if (!this.isDisposed) {
|
|
55
|
-
super.dispose();
|
|
56
|
-
|
|
57
|
-
// Ideally we would always do a reset here as we don't want different behavior between debug and release. Unfortunately, fast refresh has some strange behavior that
|
|
58
|
-
// makes it quite difficult to get this to work correctly (e.g. it re-runs previous useEffect instances, which means it can try to use Babylon Native in a de-initialized state).
|
|
59
|
-
// TODO: https://github.com/BabylonJS/BabylonReactNative/issues/125
|
|
60
|
-
if (!__DEV__) {
|
|
61
|
-
BabylonNative.reset();
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
this._isDisposed = true;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
BabylonNative.setEngineInstance(null);
|
|
68
|
-
}
|
|
69
|
-
}
|
package/index.ts
DELETED
|
Binary file
|