From aaed7af6f8ff8716a43b8c1342b6ead1b4b197c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Kwas=CC=81niewski?= Date: Fri, 20 Sep 2024 17:13:37 +0200 Subject: [PATCH] feat: add new arch --- Apps/BRNPlayground/ios/Podfile | 4 +- Apps/BRNPlayground/ios/Podfile.lock | 66 +++++++++-- Apps/BRNPlayground/package-lock.json | 1 - .../ios/BabylonEngineView.h | 17 +++ .../ios/BabylonEngineView.mm | 96 +++++++++++++++ .../ios/BabylonModule.mm | 24 +++- .../ios/BabylonNativeInterop.h | 1 + .../ios/BabylonNativeInterop.mm | 12 +- .../ios/EngineViewManager.mm | 111 +----------------- .../Fabric/BabylonEngineViewComponentView.h | 13 ++ .../Fabric/BabylonEngineViewComponentView.mm | 81 +++++++++++++ .../react-native-babylon.podspec | 2 +- .../@babylonjs/react-native/BabylonModule.ts | 27 +---- .../react-native/NativeEngineView.tsx | 17 +-- Modules/@babylonjs/react-native/package.json | 8 ++ .../spec/EngineViewNativeComponent.ts | 31 +++++ .../react-native/spec/NativeBabylonModule.ts | 9 ++ 17 files changed, 349 insertions(+), 171 deletions(-) create mode 100644 Modules/@babylonjs/react-native-iosandroid/ios/BabylonEngineView.h create mode 100644 Modules/@babylonjs/react-native-iosandroid/ios/BabylonEngineView.mm create mode 100644 Modules/@babylonjs/react-native-iosandroid/ios/Fabric/BabylonEngineViewComponentView.h create mode 100644 Modules/@babylonjs/react-native-iosandroid/ios/Fabric/BabylonEngineViewComponentView.mm create mode 100644 Modules/@babylonjs/react-native/spec/EngineViewNativeComponent.ts create mode 100644 Modules/@babylonjs/react-native/spec/NativeBabylonModule.ts diff --git a/Apps/BRNPlayground/ios/Podfile b/Apps/BRNPlayground/ios/Podfile index e1f68bd06..81d178afd 100644 --- a/Apps/BRNPlayground/ios/Podfile +++ b/Apps/BRNPlayground/ios/Podfile @@ -4,8 +4,8 @@ require_relative '../node_modules/react-native-permissions/scripts/setup' workspace 'BRNPlayground.xcworkspace' options = { - :bridgeless_enabled => false, - :fabric_enabled => false, + :bridgeless_enabled => true, + :fabric_enabled => true, :hermes_enabled => true, } diff --git a/Apps/BRNPlayground/ios/Podfile.lock b/Apps/BRNPlayground/ios/Podfile.lock index bdf5329f6..7cb42a218 100644 --- a/Apps/BRNPlayground/ios/Podfile.lock +++ b/Apps/BRNPlayground/ios/Podfile.lock @@ -1259,6 +1259,28 @@ PODS: - ReactCommon/turbomodule/core - Yoga - react-native-slider (4.5.2): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.01.01.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - react-native-slider/common (= 4.5.2) + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - react-native-slider/common (4.5.2): - DoubleConversion - glog - hermes-engine @@ -1554,6 +1576,7 @@ PODS: - React-graphics - React-ImageManager - React-NativeModulesApple + - React-RCTAppDelegate - React-RCTFabric - React-rendererdebug - React-utils @@ -1566,7 +1589,26 @@ PODS: - React-jsi - ReactTestApp-Resources (1.0.0-dev) - RNPermissions (4.1.5): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.01.01.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - SocketRocket (0.7.0) - Yoga (0.0.0) @@ -1802,16 +1844,16 @@ SPEC CHECKSUMS: React-CoreModules: 2d68c251bc4080028f2835fa47504e8f20669a21 React-cxxreact: 5f233f8ac7ea4772e49462e0ab2b0a15a4f80ab7 React-debug: fd0ed8ecd5f8a23c7daf5ceaca8aa722a4d083fd - React-defaultsnativemodule: 10f0f8bc38d8dc7d2273572cd85ed0b71298ecdd - React-domnativemodule: bfef3dda59e7030b498d0d78628f4adf414ab8e4 + React-defaultsnativemodule: 1f9a0cae1ef7e05a6ea2bbec2e5eff6eb70da16a + React-domnativemodule: 38d632c6963ab2d08f5ce67808e070439bd1461c React-Fabric: 3d0f5e2735d2f77a897ee684edeff7bb0e061919 React-FabricComponents: 68032a85a3c25c9c8d6ce676d8af9a85e2370f24 React-FabricImage: f8ac2df576703097b5b2f8d972b162cdca855aa3 React-featureflags: cf78861db9318ae29982fa8953c92d31b276c9ac - React-featureflagsnativemodule: d04eb5c3f0ac33fe70b060d97e8649bfd69c5f1e + React-featureflagsnativemodule: 99ffda7fc2cc0f9578b05b84d8b4a2e9dcb39b8b React-graphics: 7572851bca7242416b648c45d6af87d93d29281e React-hermes: 95c27801c60615345ee6256eafa6d597ce983b8b - React-idlecallbacksnativemodule: f5f0b760ec2739b30e315e1afee3dd3a5a93c3b6 + React-idlecallbacksnativemodule: e4fd9ee09b8481dd22f1e173984e5ee2730712ce React-ImageManager: aedf54d34d4475c66f4c3da6b8359b95bee904e4 React-jserrorhandler: 0c8949672a00f2a502c767350e591e3ec3d82fb3 React-jsi: d77bb442a4b0849063f2bd22d3c1fa71918713b7 @@ -1820,18 +1862,18 @@ SPEC CHECKSUMS: React-jsitracing: 3935b092f85bb1e53b8cf8a00f572413648af46b React-logger: 4072f39df335ca443932e0ccece41fbeb5ca8404 React-Mapbuffer: 714f2fae68edcabfc332b754e9fbaa8cfc68fdd4 - React-microtasksnativemodule: 4943ad8f99be8ccf5a63329fa7d269816609df9e - react-native-babylon: 6234712503667b128f2a21b17d0d6dcc03c51552 - react-native-slider: 97ce0bd921f40de79cead9754546d5e4e7ba44f8 + React-microtasksnativemodule: 0b6b90da7f203e3015e1252ec3cba49c8ddd85ad + react-native-babylon: 5ce7247a4d0d7135ad07cbff3d1ecea6658243e4 + react-native-slider: e1f4b4538f7de7417b626174874f4f58d4cf6c28 React-nativeconfig: 4a9543185905fe41014c06776bf126083795aed9 React-NativeModulesApple: 0506da59fc40d2e1e6e12a233db5e81c46face27 React-perflogger: 3bbb82f18e9ac29a1a6931568e99d6305ef4403b React-performancetimeline: d15a723422ed500f47cb271f3175abbeb217f5ba React-RCTActionSheet: cb2b38a53d03ec22f1159c89667b86c2c490d92d React-RCTAnimation: 6836c87c7364f471e9077fda80b7349bc674be33 - React-RCTAppDelegate: 2f11edfa7302451c792591f9a7838ca86cdcec34 + React-RCTAppDelegate: 603240f6a7d7eefeeffe4e29dd0be70dc35208cf React-RCTBlob: 516dbbd38397f5013394fdd1cc65408cc82e37a1 - React-RCTFabric: b281a52c2b9726b0c64880e1535f2100013d5f7c + React-RCTFabric: 7298604d497db4fe445cd704bd1097636643ee89 React-RCTImage: 1b2c2c1716db859ffff2d7a06a30b0ec5c677fc5 React-RCTLinking: 59c07577767e705b0ab95d11e5ad74c61bf2a022 React-RCTNetwork: f9a827e7d6bc428e0d99cd1fbe0427854354b8c1 @@ -1849,13 +1891,13 @@ SPEC CHECKSUMS: React-utils: f2afa6acd905ca2ce7bb8ffb4a22f7f8a12534e8 ReactCodegen: ff95a93d5ab5d9b2551571886271478eaa168565 ReactCommon: 289214026502e6a93484f4a46bcc0efa4f3f2864 - ReactNativeHost: c66372f767ef829c03a9b5ba0e3355db51c2902d + ReactNativeHost: a27bb5af1c4d73dd3e80cc7ce295407f414e0e8c ReactTestApp-DevSupport: 946bdd9e86ef05a3201d4f5af3166659f39564d0 ReactTestApp-Resources: 7db90c026cccdf40cfa495705ad436ccc4d64154 - RNPermissions: 5a2dafe37c8e0a3fa1d6e0783a1490b1b7fd92d6 + RNPermissions: d6c457e463b72e1d84e10474cd6645931338f8e5 SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d Yoga: 4ef80d96a5534f0e01b3055f17d1e19a9fc61b63 -PODFILE CHECKSUM: c0272fe43d76243a8a0abcc5781bde0430d39023 +PODFILE CHECKSUM: 777c486daf104b2094434716417a60c0da74e09e COCOAPODS: 1.15.2 diff --git a/Apps/BRNPlayground/package-lock.json b/Apps/BRNPlayground/package-lock.json index 929afd9fe..5653f3590 100644 --- a/Apps/BRNPlayground/package-lock.json +++ b/Apps/BRNPlayground/package-lock.json @@ -61,7 +61,6 @@ "@types/base-64": "^0.1.3", "@types/jest": "^25.2.1", "@types/react": "^18.2.6", - "@types/react-native": "^0.63.1", "@types/react-test-renderer": "^16.9.2", "@types/semver": "^7.3.4", "eslint": "7.12.0", diff --git a/Modules/@babylonjs/react-native-iosandroid/ios/BabylonEngineView.h b/Modules/@babylonjs/react-native-iosandroid/ios/BabylonEngineView.h new file mode 100644 index 000000000..f2f1f5057 --- /dev/null +++ b/Modules/@babylonjs/react-native-iosandroid/ios/BabylonEngineView.h @@ -0,0 +1,17 @@ +#pragma once +#import +#import +#import +#import + +@interface EngineView : MTKView + +@property (nonatomic, copy) RCTDirectEventBlock onSnapshotDataReturned; +@property (nonatomic, assign) BOOL isTransparent; +@property (nonatomic, assign) NSNumber* antiAliasing; + +- (void)setMSAA:(NSNumber*)value; +- (void)takeSnapshot; +- (void)setIsTransparentFlag:(NSNumber*)isTransparentFlag; + +@end diff --git a/Modules/@babylonjs/react-native-iosandroid/ios/BabylonEngineView.mm b/Modules/@babylonjs/react-native-iosandroid/ios/BabylonEngineView.mm new file mode 100644 index 000000000..125f83287 --- /dev/null +++ b/Modules/@babylonjs/react-native-iosandroid/ios/BabylonEngineView.mm @@ -0,0 +1,96 @@ +#import "BabylonEngineView.h" +#include "BabylonNativeInterop.h" + +@implementation EngineView { + MTKView* xrView; +} + +- (instancetype)init { + if (self = [super initWithFrame:CGRectZero device:MTLCreateSystemDefaultDevice()]) { + super.translatesAutoresizingMaskIntoConstraints = false; + super.colorPixelFormat = MTLPixelFormatBGRA8Unorm_sRGB; + super.depthStencilPixelFormat = MTLPixelFormatDepth32Float; + } + return self; +} + +- (void)setIsTransparentFlag:(NSNumber*)isTransparentFlag { + BOOL isTransparent = [isTransparentFlag intValue] == 1; + if(isTransparent){ + [self setOpaque:NO]; + } else { + [self setOpaque:YES]; + } + self.isTransparent = isTransparent; +} + +- (void)setMSAA:(NSNumber*)value { + [BabylonNativeInterop updateMSAA:value]; +} + +- (void)setBounds:(CGRect)bounds { + [super setBounds:bounds]; + [BabylonNativeInterop updateView:self]; +} + +- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { + [BabylonNativeInterop reportTouchEvent:self touches:touches event:event]; +} + +- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event { + [BabylonNativeInterop reportTouchEvent:self touches:touches event:event]; +} + +- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { + [BabylonNativeInterop reportTouchEvent:self touches:touches event:event]; +} + +- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event { + [BabylonNativeInterop reportTouchEvent:self touches:touches event:event]; +} + +- (void)drawRect:(CGRect)rect { + if ([BabylonNativeInterop isXRActive]) { + if (!xrView) { + xrView = [[MTKView alloc] initWithFrame:self.bounds device:self.device]; + xrView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + xrView.userInteractionEnabled = false; + [self addSubview:xrView]; + [BabylonNativeInterop updateXRView:xrView]; + } + } else if (xrView) { + [BabylonNativeInterop updateXRView:nil]; + [xrView removeFromSuperview]; + xrView = nil; + } + + [BabylonNativeInterop renderView]; +} + +-(void)dealloc { + [BabylonNativeInterop updateXRView:nil]; +} + +- (void)takeSnapshot { + // We must take the screenshot on the main thread otherwise we might fail to get a valid handle on the view's image. + dispatch_async(dispatch_get_main_queue(), ^{ + // Start the graphics context. + UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES /* opaque */, 0.0f); + + // Draw the current state of the view into the graphics context. + [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:NO]; + + // Grab the image from the graphics context, and convert into a base64 encoded JPG. + UIImage* capturedImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + NSData* jpgData = UIImageJPEGRepresentation(capturedImage, .8f); + NSString* encodedData = [jpgData base64EncodedStringWithOptions:0]; + + // Fire the onSnapshotDataReturned event if hooked up. + if (self.onSnapshotDataReturned != nil) { + self.onSnapshotDataReturned(@{ @"data":encodedData}); + } + }); +} + +@end diff --git a/Modules/@babylonjs/react-native-iosandroid/ios/BabylonModule.mm b/Modules/@babylonjs/react-native-iosandroid/ios/BabylonModule.mm index 295fca65a..a5c0f51a2 100644 --- a/Modules/@babylonjs/react-native-iosandroid/ios/BabylonModule.mm +++ b/Modules/@babylonjs/react-native-iosandroid/ios/BabylonModule.mm @@ -2,15 +2,25 @@ #import #import +#import + +#ifdef RCT_NEW_ARCH_ENABLED +#import +#endif #import -@interface RCTBridge (RCTTurboModule) +@interface RCTBridge (CallInvoker) - (std::shared_ptr)jsCallInvoker; @end -@interface BabylonModule : NSObject +@interface BabylonModule : NSObject +@end + +#ifdef RCT_NEW_ARCH_ENABLED +@interface BabylonModule () @end +#endif // RCT_NEW_ARCH_ENABLED @implementation BabylonModule @@ -32,4 +42,14 @@ @implementation BabylonModule }); } +- (void)invalidate { + [BabylonNativeInterop invalidate]; +} + +#ifdef RCT_NEW_ARCH_ENABLED +- (std::shared_ptr)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params { + return std::make_shared(params); +} +#endif // RCT_NEW_ARCH_ENABLED + @end diff --git a/Modules/@babylonjs/react-native-iosandroid/ios/BabylonNativeInterop.h b/Modules/@babylonjs/react-native-iosandroid/ios/BabylonNativeInterop.h index a1c192629..9ca96cc1b 100644 --- a/Modules/@babylonjs/react-native-iosandroid/ios/BabylonNativeInterop.h +++ b/Modules/@babylonjs/react-native-iosandroid/ios/BabylonNativeInterop.h @@ -5,6 +5,7 @@ @interface BabylonNativeInterop : NSObject + (void)initialize:(RCTBridge*)bridge; ++ (void)invalidate; + (void)updateView:(MTKView*)mtkView; + (void)updateMSAA:(NSNumber*)value; + (void)renderView; diff --git a/Modules/@babylonjs/react-native-iosandroid/ios/BabylonNativeInterop.mm b/Modules/@babylonjs/react-native-iosandroid/ios/BabylonNativeInterop.mm index 2ba27605a..0465d2b6a 100644 --- a/Modules/@babylonjs/react-native-iosandroid/ios/BabylonNativeInterop.mm +++ b/Modules/@babylonjs/react-native-iosandroid/ios/BabylonNativeInterop.mm @@ -37,19 +37,11 @@ + (void)initialize:(RCTBridge*)bridge { } }; BabylonNative::Initialize(*GetJSIRuntime(bridge), std::move(jsDispatcher)); - - [[NSNotificationCenter defaultCenter] removeObserver:self - name:RCTBridgeWillInvalidateModulesNotification - object:bridge.parentBridge]; - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(onBridgeWillInvalidate:) - name:RCTBridgeWillInvalidateModulesNotification - object:bridge.parentBridge]; } // NOTE: This happens during dev mode reload, when the JS engine is being shutdown and restarted. -+ (void)onBridgeWillInvalidate:(NSNotification*)notification +// It's called by RCTInvalidating. ++ (void)invalidate { BabylonNative::Deinitialize(); } diff --git a/Modules/@babylonjs/react-native-iosandroid/ios/EngineViewManager.mm b/Modules/@babylonjs/react-native-iosandroid/ios/EngineViewManager.mm index 51b1e0857..af0c3a32a 100644 --- a/Modules/@babylonjs/react-native-iosandroid/ios/EngineViewManager.mm +++ b/Modules/@babylonjs/react-native-iosandroid/ios/EngineViewManager.mm @@ -7,111 +7,10 @@ #import #import #import +#import "BabylonEngineView.h" -@interface EngineView : MTKView - -@property (nonatomic, copy) RCTDirectEventBlock onSnapshotDataReturned; -@property (nonatomic, assign) BOOL isTransparent; -@property (nonatomic, assign) NSNumber* antiAliasing; - -@end - -@implementation EngineView { - const RCTBridge* bridge; - MTKView* xrView; -} - -- (instancetype)init:(RCTBridge*)_bridge { - if (self = [super initWithFrame:CGRectZero device:MTLCreateSystemDefaultDevice()]) { - bridge = _bridge; - super.translatesAutoresizingMaskIntoConstraints = false; - super.colorPixelFormat = MTLPixelFormatBGRA8Unorm_sRGB; - super.depthStencilPixelFormat = MTLPixelFormatDepth32Float; - } - return self; -} - -- (void)setIsTransparentFlag:(NSNumber*)isTransparentFlag { - BOOL isTransparent = [isTransparentFlag intValue] == 1; - if(isTransparent){ - [self setOpaque:NO]; - } else { - [self setOpaque:YES]; - } - self.isTransparent = isTransparent; -} - -- (void)setMSAA:(NSNumber*)value { - [BabylonNativeInterop updateMSAA:value]; -} - -- (void)setBounds:(CGRect)bounds { - [super setBounds:bounds]; - [BabylonNativeInterop updateView:self]; -} - -- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { - [BabylonNativeInterop reportTouchEvent:self touches:touches event:event]; -} - -- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event { - [BabylonNativeInterop reportTouchEvent:self touches:touches event:event]; -} - -- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { - [BabylonNativeInterop reportTouchEvent:self touches:touches event:event]; -} - -- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event { - [BabylonNativeInterop reportTouchEvent:self touches:touches event:event]; -} - -- (void)drawRect:(CGRect)rect { - if ([BabylonNativeInterop isXRActive]) { - if (!xrView) { - xrView = [[MTKView alloc] initWithFrame:self.bounds device:self.device]; - xrView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - xrView.userInteractionEnabled = false; - [self addSubview:xrView]; - [BabylonNativeInterop updateXRView:xrView]; - } - } else if (xrView) { - [BabylonNativeInterop updateXRView:nil]; - [xrView removeFromSuperview]; - xrView = nil; - } - - [BabylonNativeInterop renderView]; -} - --(void)dealloc { - [BabylonNativeInterop updateXRView:nil]; -} - -- (void)takeSnapshot { - // We must take the screenshot on the main thread otherwise we might fail to get a valid handle on the view's image. - dispatch_async(dispatch_get_main_queue(), ^{ - // Start the graphics context. - UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES /* opaque */, 0.0f); - - // Draw the current state of the view into the graphics context. - [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:NO]; - - // Grab the image from the graphics context, and convert into a base64 encoded JPG. - UIImage* capturedImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - NSData* jpgData = UIImageJPEGRepresentation(capturedImage, .8f); - NSString* encodedData = [jpgData base64EncodedStringWithOptions:0]; - - // Fire the onSnapshotDataReturned event if hooked up. - if (self.onSnapshotDataReturned != nil) { - self.onSnapshotDataReturned(@{ @"data":encodedData}); - } - }); -} - -@end +#if !RCT_NEW_ARCH_ENABLED @interface EngineViewManager : RCTViewManager @end @@ -126,7 +25,7 @@ @implementation EngineViewManager [view setMSAA:json]; } -RCT_EXPORT_MODULE(EngineViewManager) +RCT_EXPORT_MODULE(EngineViewNativeComponent) RCT_EXPORT_VIEW_PROPERTY(onSnapshotDataReturned, RCTDirectEventBlock) @@ -142,7 +41,9 @@ @implementation EngineViewManager } - (UIView*)view { - return [[EngineView alloc] init:self.bridge]; + return [[EngineView alloc] init]; } @end + +#endif // !RCT_NEW_ARCH_ENABLED diff --git a/Modules/@babylonjs/react-native-iosandroid/ios/Fabric/BabylonEngineViewComponentView.h b/Modules/@babylonjs/react-native-iosandroid/ios/Fabric/BabylonEngineViewComponentView.h new file mode 100644 index 000000000..8639b1222 --- /dev/null +++ b/Modules/@babylonjs/react-native-iosandroid/ios/Fabric/BabylonEngineViewComponentView.h @@ -0,0 +1,13 @@ +#ifdef RCT_NEW_ARCH_ENABLED + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface BabylonEngineViewComponentView : RCTViewComponentView +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Modules/@babylonjs/react-native-iosandroid/ios/Fabric/BabylonEngineViewComponentView.mm b/Modules/@babylonjs/react-native-iosandroid/ios/Fabric/BabylonEngineViewComponentView.mm new file mode 100644 index 000000000..24e6da767 --- /dev/null +++ b/Modules/@babylonjs/react-native-iosandroid/ios/Fabric/BabylonEngineViewComponentView.mm @@ -0,0 +1,81 @@ +#ifdef RCT_NEW_ARCH_ENABLED + +#import "BabylonEngineViewComponentView.h" +#include +#include +#include "react/renderer/componentregistry/ComponentDescriptorProvider.h" + +#import +#import +#import +#import + +#import "RCTFabricComponentsPlugins.h" + +#import "BabylonEngineView.h" +#import "BabylonNativeInterop.h" + +using namespace facebook::react; + +@interface BabylonEngineViewComponentView () +@end + +@implementation BabylonEngineViewComponentView { + EngineView* _engineView; +} + ++ (ComponentDescriptorProvider)componentDescriptorProvider { + return concreteComponentDescriptorProvider(); +} + +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + static const auto defaultProps = std::make_shared(); + _props = defaultProps; + _engineView = [[EngineView alloc] init]; + _engineView.translatesAutoresizingMaskIntoConstraints = false; + self.contentView = _engineView; + + [NSLayoutConstraint activateConstraints:@[ + [_engineView.topAnchor constraintEqualToAnchor:self.topAnchor], + [_engineView.leftAnchor constraintEqualToAnchor:self.leftAnchor], + [_engineView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor], + [_engineView.rightAnchor constraintEqualToAnchor:self.rightAnchor], + ]]; + } + return self; +} + +- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps +{ + const auto &oldViewProps = *std::static_pointer_cast(_props); + const auto &newViewProps = *std::static_pointer_cast(props); + + if (oldViewProps.isTransparent != newViewProps.isTransparent) { + [_engineView setIsTransparentFlag:[NSNumber numberWithBool:newViewProps.isTransparent]]; + } + + if (oldViewProps.antiAliasing != newViewProps.antiAliasing) { + [_engineView setMSAA:[NSNumber numberWithInt:newViewProps.antiAliasing]]; + } + + [super updateProps:props oldProps:oldProps]; +} + +- (void)prepareForRecycle +{ + [super prepareForRecycle]; + _engineView = nil; +} + +- (void)takeSnapshot { + [_engineView takeSnapshot]; +} + +@end + +Class EngineViewNativeComponentCls(void) { + return BabylonEngineViewComponentView.class; +} + +#endif diff --git a/Modules/@babylonjs/react-native-iosandroid/react-native-babylon.podspec b/Modules/@babylonjs/react-native-iosandroid/react-native-babylon.podspec index db7ae2435..0886271b4 100644 --- a/Modules/@babylonjs/react-native-iosandroid/react-native-babylon.podspec +++ b/Modules/@babylonjs/react-native-iosandroid/react-native-babylon.podspec @@ -15,7 +15,7 @@ Pod::Spec.new do |s| s.platforms = { :ios => "12.0" } s.source = { :git => package["repository"]["url"], :tag => s.version } - s.source_files = "ios/*.{h,m,mm}" + s.source_files = "ios/**/*.{h,m,mm}" s.requires_arc = true s.xcconfig = { 'USER_HEADER_SEARCH_PATHS' => '$(inherited) ${PODS_TARGET_SRCROOT}/shared ${PODS_TARGET_SRCROOT}/../react-native/shared' } diff --git a/Modules/@babylonjs/react-native/BabylonModule.ts b/Modules/@babylonjs/react-native/BabylonModule.ts index 860f9aadf..b81906b3d 100644 --- a/Modules/@babylonjs/react-native/BabylonModule.ts +++ b/Modules/@babylonjs/react-native/BabylonModule.ts @@ -1,29 +1,10 @@ -import { NativeModules } from 'react-native'; - -declare const global: { - nativeCallSyncHook: any; -}; -const isRemoteDebuggingEnabled = !global.nativeCallSyncHook; - -// This legacy React Native module is created by Babylon React Native, and is only used to bootstrap the JSI object creation. -// This will likely be removed when the BabylonNative global object is eventually converted to a TurboModule. -const BabylonModule: { - initialize(): Promise; - resetView(): Promise; -} = NativeModules.BabylonModule; +import BabylonModule from './spec/NativeBabylonModule'; export async function ensureInitialized(): Promise { - if (isRemoteDebuggingEnabled) { - // When remote debugging is enabled, JavaScript runs on the debugging host machine, not on the device where the app is running. - // JSI (which Babylon Native uses heavily) can not work in this mode. In the future, this debugging mode will be phased out as it is incompatible with TurboModules for the same reason. - return false; - } else { - // This does the first stage of Babylon Native initialization, including creating the BabylonNative JSI object. - await BabylonModule.initialize(); - return true; - } + await BabylonModule.initialize(); + return true; } export async function reset(): Promise { return BabylonModule.resetView(); -} \ No newline at end of file +} diff --git a/Modules/@babylonjs/react-native/NativeEngineView.tsx b/Modules/@babylonjs/react-native/NativeEngineView.tsx index c0688b310..e2efb9c85 100644 --- a/Modules/@babylonjs/react-native/NativeEngineView.tsx +++ b/Modules/@babylonjs/react-native/NativeEngineView.tsx @@ -1,16 +1,3 @@ -import { Component, SyntheticEvent } from 'react'; -import { requireNativeComponent, ViewProps } from 'react-native'; +import EngineView from './spec/EngineViewNativeComponent' -declare const global: any; - -export interface NativeEngineViewProps extends ViewProps { - isTransparent: boolean; - antiAliasing: number; - androidView: string; - onSnapshotDataReturned?: (event: SyntheticEvent) => void; -} - -export const NativeEngineView: { - prototype: Component; - new(props: Readonly): Component; -} = global['EngineView'] || (global['EngineView'] = requireNativeComponent('EngineView')); +export { EngineView as NativeEngineView }; diff --git a/Modules/@babylonjs/react-native/package.json b/Modules/@babylonjs/react-native/package.json index f5d6e330f..3a863af7f 100644 --- a/Modules/@babylonjs/react-native/package.json +++ b/Modules/@babylonjs/react-native/package.json @@ -51,5 +51,13 @@ "metro-react-native-babel-preset": "^0.56.0", "prettier": "1.19.1", "typescript": "^4.3.5" + }, + "codegenConfig": { + "name": "BabylonModuleSpec", + "type": "all", + "jsSrcsDir": "spec", + "android": { + "javaPackageName": "com.babylonreactnative" + } } } diff --git a/Modules/@babylonjs/react-native/spec/EngineViewNativeComponent.ts b/Modules/@babylonjs/react-native/spec/EngineViewNativeComponent.ts new file mode 100644 index 000000000..471a32a3f --- /dev/null +++ b/Modules/@babylonjs/react-native/spec/EngineViewNativeComponent.ts @@ -0,0 +1,31 @@ +import type { HostComponent, ViewProps } from 'react-native'; +import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands'; +import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent'; + +import type { + DirectEventHandler, + WithDefault, + Int32 +} from 'react-native/Libraries/Types/CodegenTypes'; + +export interface NativeProps extends ViewProps { + isTransparent?: WithDefault; + antiAliasing?: Int32; + onSnapshotDataReturned?: DirectEventHandler; +} + +type EngineViewViewType = HostComponent; + +export interface NativeCommands { + takeSnapshot: (viewRef: React.ElementRef) => Promise; +} + +export const Commands: NativeCommands = codegenNativeCommands({ + supportedCommands: [ + 'takeSnapshot' + ], +}); + +export default codegenNativeComponent( + 'EngineViewNativeComponent' +) as HostComponent; diff --git a/Modules/@babylonjs/react-native/spec/NativeBabylonModule.ts b/Modules/@babylonjs/react-native/spec/NativeBabylonModule.ts new file mode 100644 index 000000000..14fd906af --- /dev/null +++ b/Modules/@babylonjs/react-native/spec/NativeBabylonModule.ts @@ -0,0 +1,9 @@ +import type {TurboModule} from 'react-native'; +import {TurboModuleRegistry} from 'react-native'; + +export interface Spec extends TurboModule { + initialize(): Promise; + resetView(): Promise; +} + +export default TurboModuleRegistry.get("BabylonModule");