diff --git a/Modules/@babylonjs/react-native-iosandroid/android/src/main/java/com/babylonreactnative/EngineView.java b/Modules/@babylonjs/react-native-iosandroid/android/src/main/java/com/babylonreactnative/EngineView.java index f373a0f61..0ff5c29fd 100644 --- a/Modules/@babylonjs/react-native-iosandroid/android/src/main/java/com/babylonreactnative/EngineView.java +++ b/Modules/@babylonjs/react-native-iosandroid/android/src/main/java/com/babylonreactnative/EngineView.java @@ -33,14 +33,14 @@ public final class EngineView extends FrameLayout implements SurfaceHolder.Callb private SurfaceView xrSurfaceView; private boolean isTransparent = false; - private boolean isTopMost = false; + private String androidView = ""; private final EventDispatcher reactEventDispatcher; private Runnable renderRunnable; public EngineView(ReactContext reactContext) { super(reactContext); - this.setIsTransparentAndIsTopMost(false, false); + this.setIsTransparentAndAndroidView(false, ""); this.xrSurfaceView = new SurfaceView(reactContext); this.xrSurfaceView.setLayoutParams(childViewLayoutParams); @@ -72,17 +72,18 @@ public void setAntiAliasing(Integer value) { BabylonNativeInterop.updateMSAA(value); } - public void setIsTopMost(Boolean isTopMost) { - setIsTransparentAndIsTopMost(this.isTransparent, isTopMost); - } // ------------------------------------ - // TextureView related + + public void setAndroidView(String androidView) { + setIsTransparentAndAndroidView(this.isTransparent, androidView); + } + public void setIsTransparent(Boolean isTransparent) { - setIsTransparentAndIsTopMost(isTransparent, this.isTopMost); + setIsTransparentAndAndroidView(isTransparent, this.androidView); } - private void setIsTransparentAndIsTopMost(Boolean isTransparent, Boolean isTopMost) { - if (this.isTransparent == isTransparent && this.isTopMost == isTopMost && + private void setIsTransparentAndAndroidView(Boolean isTransparent, String androidView) { + if (this.isTransparent == isTransparent && this.androidView.equals(androidView) && (this.surfaceView != null || this.transparentTextureView != null)) { return; } @@ -94,30 +95,34 @@ private void setIsTransparentAndIsTopMost(Boolean isTransparent, Boolean isTopMo this.transparentTextureView.setVisibility(View.GONE); this.transparentTextureView = null; } - if (isTransparent && !isTopMost) { + + if (androidView.equals("TextureView")) { this.transparentTextureView = new TextureView(this.getContext()); this.transparentTextureView.setLayoutParams(EngineView.childViewLayoutParams); this.transparentTextureView.setSurfaceTextureListener(this); - this.transparentTextureView.setOpaque(false); + this.transparentTextureView.setOpaque(isTransparent); this.addView(this.transparentTextureView); } else { this.surfaceView = new SurfaceView(this.getContext()); this.surfaceView.setLayoutParams(EngineView.childViewLayoutParams); SurfaceHolder surfaceHolder = this.surfaceView.getHolder(); + if (isTransparent) { + // transparent and androidView equals "SurfaceView" will give an opaque SurfaceView surfaceHolder.setFormat(PixelFormat.TRANSPARENT); } - if (isTopMost) { - // ZOrder is not dynamic before Android 11. Recreate the surfaceView and set order before adding to the parent - // https://developer.android.com/reference/android/view/SurfaceView#setZOrderOnTop(boolean) + if ((androidView.equals("") && isTransparent) || androidView.equals("SurfaceViewZTopMost")) { this.surfaceView.setZOrderOnTop(true); + } else if (androidView.equals("SurfaceViewZMediaOverlay")) { + this.surfaceView.setZOrderMediaOverlay(true); } + surfaceHolder.addCallback(this); this.addView(this.surfaceView); } this.isTransparent = isTransparent; - this.isTopMost = isTopMost; + this.androidView = androidView; // xr view needs to be on top of views that might be created after it. if (this.xrSurfaceView != null) { diff --git a/Modules/@babylonjs/react-native-iosandroid/android/src/main/java/com/babylonreactnative/EngineViewManager.java b/Modules/@babylonjs/react-native-iosandroid/android/src/main/java/com/babylonreactnative/EngineViewManager.java index 3849d28cb..15af178af 100644 --- a/Modules/@babylonjs/react-native-iosandroid/android/src/main/java/com/babylonreactnative/EngineViewManager.java +++ b/Modules/@babylonjs/react-native-iosandroid/android/src/main/java/com/babylonreactnative/EngineViewManager.java @@ -33,9 +33,9 @@ public void setAntiAliasing(EngineView view, Integer value) { view.setAntiAliasing(value); } - @ReactProp(name = "isTopMost") - public void setIsTopMost(EngineView view, Boolean isTopMost) { - view.setIsTopMost(isTopMost); + @ReactProp(name = "androidView") + public void setAndroidView(EngineView view, String androidView) { + view.setAndroidView(androidView); } @NonNull diff --git a/Modules/@babylonjs/react-native-iosandroid/ios/EngineViewManager.mm b/Modules/@babylonjs/react-native-iosandroid/ios/EngineViewManager.mm index 471a342a3..51b1e0857 100644 --- a/Modules/@babylonjs/react-native-iosandroid/ios/EngineViewManager.mm +++ b/Modules/@babylonjs/react-native-iosandroid/ios/EngineViewManager.mm @@ -13,7 +13,6 @@ @interface EngineView : MTKView @property (nonatomic, copy) RCTDirectEventBlock onSnapshotDataReturned; @property (nonatomic, assign) BOOL isTransparent; @property (nonatomic, assign) NSNumber* antiAliasing; -@property (nonatomic, assign) BOOL isTopMost; @end @@ -46,12 +45,6 @@ - (void)setMSAA:(NSNumber*)value { [BabylonNativeInterop updateMSAA:value]; } -- (void)setIsTopMostFlag:(NSNumber*)isTopMostFlag { - BOOL isTopMost = [isTopMostFlag intValue] == 1; - self.layer.zPosition = isTopMost ? FLT_MAX : 0.f; - self.isTopMost = isTopMost; -} - - (void)setBounds:(CGRect)bounds { [super setBounds:bounds]; [BabylonNativeInterop updateView:self]; @@ -133,10 +126,6 @@ @implementation EngineViewManager [view setMSAA:json]; } -RCT_CUSTOM_VIEW_PROPERTY(isTopMost, NSNumber*, EngineView){ - [view setIsTopMostFlag:json]; -} - RCT_EXPORT_MODULE(EngineViewManager) RCT_EXPORT_VIEW_PROPERTY(onSnapshotDataReturned, RCTDirectEventBlock) diff --git a/Modules/@babylonjs/react-native-windows/windows/BabylonReactNative/EngineView.cpp b/Modules/@babylonjs/react-native-windows/windows/BabylonReactNative/EngineView.cpp index 2ccdb2c16..fe5649a9b 100644 --- a/Modules/@babylonjs/react-native-windows/windows/BabylonReactNative/EngineView.cpp +++ b/Modules/@babylonjs/react-native-windows/windows/BabylonReactNative/EngineView.cpp @@ -188,9 +188,6 @@ namespace winrt::BabylonReactNative::implementation { { auto value = propertyValue.AsUInt8(); BabylonNative::UpdateMSAA(value); - } else if (propertyName == "isTopMost") - { - // todo: implementation } } } diff --git a/Modules/@babylonjs/react-native-windows/windows/BabylonReactNative/EngineViewManager.cpp b/Modules/@babylonjs/react-native-windows/windows/BabylonReactNative/EngineViewManager.cpp index ff8dad186..1517483d9 100644 --- a/Modules/@babylonjs/react-native-windows/windows/BabylonReactNative/EngineViewManager.cpp +++ b/Modules/@babylonjs/react-native-windows/windows/BabylonReactNative/EngineViewManager.cpp @@ -38,7 +38,6 @@ namespace winrt::BabylonReactNative::implementation { nativeProps.Insert(L"isTransparent", ViewManagerPropertyType::Boolean); nativeProps.Insert(L"antiAliasing", ViewManagerPropertyType::Number); - nativeProps.Insert(L"isTopMost", ViewManagerPropertyType::Boolean); return nativeProps.GetView(); } diff --git a/Modules/@babylonjs/react-native/EngineView.tsx b/Modules/@babylonjs/react-native/EngineView.tsx index 1ede5fddb..15956f4b3 100644 --- a/Modules/@babylonjs/react-native/EngineView.tsx +++ b/Modules/@babylonjs/react-native/EngineView.tsx @@ -9,7 +9,7 @@ export interface EngineViewProps extends ViewProps { camera?: Camera; displayFrameRate?: boolean; isTransparent?: boolean; - isTopMost?: boolean; + androidView?: "TextureView" | "SurfaceView" | "SurfaceViewZTopMost" | "SurfaceViewZMediaOverlay"; antiAliasing?: 0 | 1 | 2 | 4 | 8 | 16; onInitialized?: (view: EngineViewCallbacks) => void; } @@ -30,7 +30,7 @@ export const EngineView: FunctionComponent = (props: EngineView const snapshotPromise = useRef<{ promise: Promise, resolve: (data: string) => void }>(); const isTransparent = props.isTransparent ?? false; const antiAliasing = props.antiAliasing ?? 0; - const isTopMost = props.isTopMost ?? false; + const androidView = props.androidView ?? ""; const initialized = useModuleInitializer(); @@ -116,7 +116,7 @@ export const EngineView: FunctionComponent = (props: EngineView if (initialized !== false) { return ( - { initialized && } + { initialized && } { sceneStats !== undefined && FPS: {sceneStats.frameRate.toFixed(0)} diff --git a/Modules/@babylonjs/react-native/NativeEngineView.tsx b/Modules/@babylonjs/react-native/NativeEngineView.tsx index b30f280f1..c0688b310 100644 --- a/Modules/@babylonjs/react-native/NativeEngineView.tsx +++ b/Modules/@babylonjs/react-native/NativeEngineView.tsx @@ -6,7 +6,7 @@ declare const global: any; export interface NativeEngineViewProps extends ViewProps { isTransparent: boolean; antiAliasing: number; - isTopMost: boolean; + androidView: string; onSnapshotDataReturned?: (event: SyntheticEvent) => void; } diff --git a/Modules/@babylonjs/react-native/README.md b/Modules/@babylonjs/react-native/README.md index 081f976d5..c297dff7c 100644 --- a/Modules/@babylonjs/react-native/README.md +++ b/Modules/@babylonjs/react-native/README.md @@ -89,14 +89,6 @@ e.g. ```tsx ``` -`isTopMost` is a flag that allows to place the view on top of any other view. When enabled, this allows a huge performance improvement on Android with Transparency on. - -e.g. - -```tsx - -``` - To configure anti-aliasing, a property called `antiAliasing` can be changed to a value of 0 or 1 (disable anti-aliasing, default), 2, 4, 8 or 16 (anti-aliasing samples). e.g. @@ -106,3 +98,19 @@ e.g. ``` Note: Currently only one `EngineView` can be active at any given time. Multi-view will be supported in a future release. + +The Android specific `androidView` property can help set the type of the view used for rendering. Depending on user needs and performance, refer to the table below. [`TextureView`](https://developer.android.com/reference/android/view/TextureView) can be inserted anywhere in the view hierarchy, but is less efficient. [`SurfaceView`](https://developer.android.com/reference/android/view/SurfaceView) can only be full above or fully below the rest of the UI, but is more efficient. + +| isTransparent | androidView | Description | +| ----------- | ------------------------ | ----------- | +| False | TextureView | Opaque TextureView. +| False | SurfaceView | Simple surfaceView (default when no `androidView` set with `isTransparent=false`). +| False | SurfaceViewZTopMost | SurfaceView with [ZTopMost](https://developer.android.com/reference/android/view/SurfaceView#setZOrderOnTop(boolean)) set to `true`. +| False | SurfaceViewZMediaOverlay | SurfaceView with [ZMediaOverlay](https://developer.android.com/reference/android/view/SurfaceView#setZOrderMediaOverlay(boolean)) set to `true`. +| True | TextureView | Transparent TextureView. +| True | SurfaceView | SurfaceView will stay opaque +| True | SurfaceViewZTopMost | SurfaceView with [ZTopMost](https://developer.android.com/reference/android/view/SurfaceView#setZOrderOnTop(boolean)) set to `true`. Transparent but top most. (default when no `androidView` set with `isTransparent=true`) +| True | SurfaceViewZMediaOverlay | SurfaceView with [ZMediaOverlay](https://developer.android.com/reference/android/view/SurfaceView#setZOrderMediaOverlay(boolean)) set to `true`. Only Transparent on top of other SurfaceViews. + +More infos on TextureView Vs SurfaceView performance here: +https://developer.android.com/reference/android/view/TextureView