From 8288758e78bc8281e836e258941f2230e1fd0fa3 Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Thu, 16 Sep 2021 17:33:24 +0800 Subject: [PATCH] tidy up method call handler and add example project with camera panning --- example/ios/Runner.xcodeproj/project.pbxproj | 15 +++ example/lib/main.dart | 56 +++++++---- example/pubspec.yaml | 16 ++- .../filament/FilamentMethodCallHandler.h | 23 +++++ .../filament/FilamentMethodCallHandler.mm | 97 +++++++++++++++++++ .../filament/FilamentNativeViewFactory.h | 10 +- .../filament/FilamentNativeViewFactory.mm | 87 ++--------------- ios/Classes/filament/FilamentView.h | 5 +- ios/Classes/filament/FilamentView.mm | 27 +++++- ios/Classes/filament/FilamentViewController.h | 5 +- .../filament/FilamentViewController.mm | 19 +++- ios/mimetic_filament.podspec | 11 ++- ios/src/FilamentViewer.cpp | 89 +++++++++++++++-- ios/src/FilamentViewer.hpp | 18 +++- lib/filament_controller.dart | 24 ++++- pubspec.yaml | 2 + 16 files changed, 363 insertions(+), 141 deletions(-) create mode 100644 ios/Classes/filament/FilamentMethodCallHandler.h create mode 100644 ios/Classes/filament/FilamentMethodCallHandler.mm diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index d3759bfd..ea956665 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -310,6 +310,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -324,6 +325,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + STRIP_INSTALLED_PRODUCT = NO; SUPPORTED_PLATFORMS = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; @@ -337,6 +339,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = 873X6R39HP; ENABLE_BITCODE = NO; GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp; @@ -345,8 +348,10 @@ "$(inherited)", "@executable_path/Frameworks", ); + PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES; PRODUCT_BUNDLE_IDENTIFIER = com.example.mimeticAvatarExample; PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -383,6 +388,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -404,6 +410,7 @@ MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; + STRIP_INSTALLED_PRODUCT = NO; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -438,6 +445,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -452,6 +460,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + STRIP_INSTALLED_PRODUCT = NO; SUPPORTED_PLATFORMS = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; @@ -467,6 +476,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = 873X6R39HP; ENABLE_BITCODE = NO; GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp; @@ -475,8 +485,10 @@ "$(inherited)", "@executable_path/Frameworks", ); + PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES; PRODUCT_BUNDLE_IDENTIFIER = com.example.mimeticAvatarExample; PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -491,6 +503,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = 873X6R39HP; ENABLE_BITCODE = NO; GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp; @@ -499,8 +512,10 @@ "$(inherited)", "@executable_path/Frameworks", ); + PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES; PRODUCT_BUNDLE_IDENTIFIER = com.example.mimeticAvatarExample; PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; diff --git a/example/lib/main.dart b/example/lib/main.dart index 06ebb516..b029fad2 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -18,7 +18,6 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { final FilamentController _filamentController = MimeticFilamentController(); - String _platformVersion = 'Unknown'; @override void initState() { @@ -32,23 +31,44 @@ class _MyAppState extends State { appBar: AppBar( title: const Text('Plugin example app'), ), - body: Stack(children: [ - FilamentWidget(controller: _filamentController), - Column(children: [ - ElevatedButton( - child: Text("initialize"), - onPressed: () { - _filamentController.initialize(); - }), - ElevatedButton( - child: Text("load asset"), - onPressed: () { - _filamentController.loadSkybox( - "assets/default_env/default_env_skybox.ktx", - "assets/default_env/default_env_ibl.ktx"); - }), - ]), - ]), + body: GestureDetector( + behavior: HitTestBehavior.opaque, + onPanDown: (details) { + _filamentController.panStart( + details.localPosition.dx, details.localPosition.dy); + }, + onPanUpdate: (details) { + print(details.localPosition.dx); + _filamentController.panUpdate( + details.localPosition.dx, details.localPosition.dy); + }, + onPanEnd: (d) { + _filamentController.panEnd(); + }, + child: Stack(children: [ + FilamentWidget(controller: _filamentController), + Column(children: [ + ElevatedButton( + child: Text("initialize"), + onPressed: () { + _filamentController.initialize(); + }), + ElevatedButton( + child: Text("load skybox"), + onPressed: () { + _filamentController.loadSkybox( + "assets/default_env/default_env_skybox.ktx", + "assets/default_env/default_env_ibl.ktx"); + }), + ElevatedButton( + child: Text("load gltf"), + onPressed: () { + _filamentController.loadGltf( + "assets/BusterDrone/scene.gltf", + "assets/BusterDrone"); + }), + ]), + ])), ), ); } diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 354966cc..aa7dcf95 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -39,16 +39,14 @@ dev_dependencies: # The following section is specific to Flutter. flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg + assets: + - assets/ + - assets/default_env/ + - assets/BusterDrone/ + - assets/BusterDrone/textures/ + - assets/FlightHelmet/ + - assets/FlightHelmet/textures/ # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware. diff --git a/ios/Classes/filament/FilamentMethodCallHandler.h b/ios/Classes/filament/FilamentMethodCallHandler.h new file mode 100644 index 00000000..ea4fa788 --- /dev/null +++ b/ios/Classes/filament/FilamentMethodCallHandler.h @@ -0,0 +1,23 @@ +#ifndef FilamentMethodCallHandler_h +#define FilamentMethodCallHandler_h +#endif /* FilamentNativeViewFactory_h */ + +#import +#import "FilamentViewController.h" + +#include "FilamentViewer.hpp" + +static const id VIEW_TYPE = @"mimetic.app/filament_view"; + +@interface FilamentMethodCallHandler : FlutterMethodChannel +- (void)handleMethodCall:(FlutterMethodCall* _Nonnull)call result:( FlutterResult _Nonnull)result; +- (mimetic::FilamentViewer*) _viewer; +- (mimetic::ResourceBuffer)loadResource:(const char* const)path; +- (void)freeResource:(void*)mem size:(size_t)size misc:(void*)misc; + +- (instancetype)initWithController:(FilamentViewController*)controller + registrar:(NSObject*)registrar + viewId:(int64_t)viewId + layer:(void*)layer; + +@end diff --git a/ios/Classes/filament/FilamentMethodCallHandler.mm b/ios/Classes/filament/FilamentMethodCallHandler.mm new file mode 100644 index 00000000..bed066a1 --- /dev/null +++ b/ios/Classes/filament/FilamentMethodCallHandler.mm @@ -0,0 +1,97 @@ +#import "FilamentMethodCallHandler.h" +#import "FilamentViewController.h" +#import "FilamentNativeViewFactory.h" + +static const FilamentMethodCallHandler* _handler; + +static mimetic::ResourceBuffer loadResourceGlobal(const char* name) { + return [_handler loadResource:name]; +} + +static void* freeResourceGlobal(void* mem, size_t size, void* misc) { + [_handler freeResource:mem size:size misc:misc ]; + return nullptr; +} + +@implementation FilamentMethodCallHandler { + FilamentViewController *_controller; + FlutterMethodChannel* _channel; + mimetic::FilamentViewer* _viewer; + void* _layer; + + NSObject* _registrar; +} +- (instancetype)initWithController:(FilamentViewController*)controller + registrar:(NSObject*)registrar + viewId:(int64_t)viewId + layer:(void*)layer +{ + _layer = layer; + _registrar = registrar; + _controller = controller; + NSString* channelName = [NSString stringWithFormat:@"%@_%d",VIEW_TYPE,viewId]; + _channel = [FlutterMethodChannel + methodChannelWithName:channelName + binaryMessenger:[registrar messenger]]; + [_channel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) { + [self handleMethodCall:call result:result]; + }]; + _handler = self; + return self; +} + +- (void)handleMethodCall:(FlutterMethodCall* _Nonnull)call result:(FlutterResult _Nonnull )result { + if([@"initialize" isEqualToString:call.method]) { + _viewer = new mimetic::FilamentViewer(_layer, loadResourceGlobal, freeResourceGlobal); + [_controller setViewer:_viewer]; + [_controller startDisplayLink]; + result(@"OK"); + } else if([@"loadSkybox" isEqualToString:call.method]) { + if(!_viewer) + return; + _viewer->loadSkybox([call.arguments[0] UTF8String], [call.arguments[1] UTF8String]); + result(@"OK"); + } else if([@"loadGltf" isEqualToString:call.method]) { + if(!_viewer) + return; + _viewer->loadGltf([call.arguments[0] UTF8String], [call.arguments[1] UTF8String]); + result(@"OK"); + } else if([@"panStart" isEqualToString:call.method]) { + if(!_viewer) + return; + _viewer->manipulator->grabBegin([call.arguments[0] intValue], [call.arguments[1] intValue], true); + } else if([@"panUpdate" isEqualToString:call.method]) { + if(!_viewer) + return; + _viewer->manipulator->grabUpdate([call.arguments[0] intValue], [call.arguments[1] intValue]); + } else if([@"panEnd" isEqualToString:call.method]) { + if(!_viewer) + return; + _viewer->manipulator->grabEnd(); + } else { + result(FlutterMethodNotImplemented); + } +} + +- (mimetic::ResourceBuffer)loadResource:(const char* const)path { + NSString* p = [NSString stringWithFormat:@"%s", path]; + NSString* key = [_registrar lookupKeyForAsset:p]; + NSString* nsPath = [[NSBundle mainBundle] pathForResource:key + ofType:nil]; + if (![[NSFileManager defaultManager] fileExistsAtPath:nsPath]) { + NSLog(@"Error: no file exists at %@", nsPath); + exit(-1); + } + + NSData* buffer = [NSData dataWithContentsOfFile:nsPath]; + void* cpy = malloc([buffer length]); + memcpy(cpy, [buffer bytes], [buffer length]); // can we avoid this copy somehow? + mimetic::ResourceBuffer rbuf(cpy, [buffer length]); + return rbuf; +} + +- (void)freeResource:(void*)mem size:(size_t)s misc:(void *)m { + free(mem); +} + +@end diff --git a/ios/Classes/filament/FilamentNativeViewFactory.h b/ios/Classes/filament/FilamentNativeViewFactory.h index 1835ec08..3a2a9d27 100644 --- a/ios/Classes/filament/FilamentNativeViewFactory.h +++ b/ios/Classes/filament/FilamentNativeViewFactory.h @@ -3,17 +3,13 @@ #endif /* FilamentNativeViewFactory_h */ #import -#import "FilamentViewer.hpp" +#import "FilamentView.h" + +#include "FilamentViewer.hpp" -@interface FilamentMethodCallHandler : FlutterMethodChannel -- (void)handleMethodCall:(FlutterMethodCall* _Nonnull)call result:( FlutterResult _Nonnull)result; -- (mimetic::FilamentViewer*) _viewer; -@end @interface FilamentNativeViewFactory : NSObject - (instancetype)initWithRegistrar:(NSObject*)registrar; -- (mimetic::ResourceBuffer)loadResource:(const char* const)path; -- (void)freeResource:(void*)mem size:(size_t)size misc:(void*)misc; @end @interface FilamentNativeView : NSObject diff --git a/ios/Classes/filament/FilamentNativeViewFactory.mm b/ios/Classes/filament/FilamentNativeViewFactory.mm index caff7174..037e74e6 100644 --- a/ios/Classes/filament/FilamentNativeViewFactory.mm +++ b/ios/Classes/filament/FilamentNativeViewFactory.mm @@ -1,18 +1,6 @@ #import "FilamentNativeViewFactory.h" #import "FilamentViewController.h" - -static const id VIEW_TYPE = @"mimetic.app/filament_view"; - -static const FilamentNativeViewFactory* _factory; - -static mimetic::ResourceBuffer loadResource(const char* const name) { - return [_factory loadResource:name]; -} - -static void* freeResource(void* mem, size_t size, void* misc) { - [_factory freeResource:mem size:size misc:misc ]; - return nullptr; -} +#import "FilamentMethodCallHandler.h" @implementation FilamentNativeViewFactory { NSObject* _registrar; @@ -23,7 +11,6 @@ static void* freeResource(void* mem, size_t size, void* misc) { if (self) { _registrar = registrar; } - _factory = self; return self; } @@ -38,81 +25,27 @@ static void* freeResource(void* mem, size_t size, void* misc) { @end -@implementation FilamentMethodCallHandler { - FilamentViewController *_controller; - FlutterMethodChannel* _channel; - mimetic::FilamentViewer* _viewer; - void* _layer; -} -- (instancetype)initWithController:(FilamentViewController*)controller - registrar:(NSObject*)registrar - viewId:(int64_t)viewId - layer:(void*)layer - { - _layer = layer; - _controller = controller; - NSString* channelName = [NSString stringWithFormat:@"%@_%d",VIEW_TYPE,viewId]; - _channel = [FlutterMethodChannel - methodChannelWithName:channelName - binaryMessenger:[registrar messenger]]; - [_channel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) { - [self handleMethodCall:call result:result]; - }]; - return self; -} -- (void)handleMethodCall:(FlutterMethodCall* _Nonnull)call result:(FlutterResult _Nonnull )result { - if([@"initialize" isEqualToString:call.method]) { - [self initialize]; - } else { - result(FlutterMethodNotImplemented); - } -} - -- (mimetic::ResourceBuffer)loadResource:(const char* const)path { - - NSString* documentPath = [NSSearchPathForDirectoriesInDomains( - NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; - NSString* pathComponent = [NSString stringWithUTF8String:path]; - NSString* nsPath = [documentPath stringByAppendingPathComponent:pathComponent]; - - if (![[NSFileManager defaultManager] fileExistsAtPath:nsPath]) { - NSLog(@"Error: no file exists at %@", nsPath); - exit(-1); - } - - NSData* buffer = [NSData dataWithContentsOfFile:nsPath]; - - mimetic::ResourceBuffer rbuf([buffer bytes], [buffer length]); - return rbuf; -} - -- (void)freeResource:(void*)mem size:(size_t)s misc:(void *)m { - // TODO -} - --(void)initialize { - _viewer = new mimetic::FilamentViewer(_layer, loadResource, freeResource); -} -@end @implementation FilamentNativeView { - FilamentView *_view; - FilamentViewController *_controller; - FilamentMethodCallHandler *_handler; + FilamentView* _view; + FilamentViewController* _controller; + mimetic::FilamentViewer* _viewer; + FilamentMethodCallHandler* _handler; + void* _layer; } + - (instancetype)initWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id _Nullable)args registrar:(NSObject*)registrar { if (self = [super init]) { _view = [[FilamentView alloc] init]; - _controller = [[FilamentViewController alloc] initWithRegistrar:registrar]; - _controller.modelView = _view; + _controller = [[FilamentViewController alloc] initWithRegistrar:registrar view:_view]; [_controller viewDidLoad]; - [_controller startDisplayLink]; - _handler = [[FilamentMethodCallHandler alloc] initWithController:_controller registrar:registrar viewId:viewId layer:(__bridge void*)[_view layer]]; + _layer = (__bridge_retained void*)[_view layer]; + _handler = [[FilamentMethodCallHandler alloc] initWithController:_controller registrar:registrar viewId:viewId layer:_layer]; } return self; } diff --git a/ios/Classes/filament/FilamentView.h b/ios/Classes/filament/FilamentView.h index 306b8551..103e9378 100644 --- a/ios/Classes/filament/FilamentView.h +++ b/ios/Classes/filament/FilamentView.h @@ -15,7 +15,7 @@ */ #import - +#include "FilamentViewer.hpp" NS_ASSUME_NONNULL_BEGIN /** @@ -24,8 +24,7 @@ NS_ASSUME_NONNULL_BEGIN * */ @interface FilamentView : UIView - - +- (void)setViewer:(mimetic::FilamentViewer*)viewer; @end NS_ASSUME_NONNULL_END diff --git a/ios/Classes/filament/FilamentView.mm b/ios/Classes/filament/FilamentView.mm index 20c2082c..22ed970a 100644 --- a/ios/Classes/filament/FilamentView.mm +++ b/ios/Classes/filament/FilamentView.mm @@ -16,21 +16,26 @@ // These defines are set in the "Preprocessor Macros" build setting for each scheme. #include "FilamentView.h" - +#include "FilamentViewer.hpp" #import using namespace std; @interface FilamentView () - - (void)initCommon; - +- (void)setViewer:(mimetic::FilamentViewer*)viewer; @end @implementation FilamentView { - + mimetic::FilamentViewer* _viewer; } +- (void)setViewer:(mimetic::FilamentViewer*)viewer { + _viewer = viewer; + _viewer->updateViewportAndCameraProjection(self.bounds.size.width, self.bounds.size.height, self.contentScaleFactor); +} + + - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { [self initCommon]; @@ -58,4 +63,18 @@ using namespace std; return [CAEAGLLayer class]; } +- (void)layoutSubviews { + [super layoutSubviews]; + if(_viewer) { + _viewer->updateViewportAndCameraProjection(self.bounds.size.width, self.bounds.size.height, self.contentScaleFactor); + } +} + +- (void)setContentScaleFactor:(CGFloat)contentScaleFactor { + [super setContentScaleFactor:contentScaleFactor]; + if(_viewer) { + _viewer->updateViewportAndCameraProjection(self.bounds.size.width, self.bounds.size.height, self.contentScaleFactor); + } +} + @end diff --git a/ios/Classes/filament/FilamentViewController.h b/ios/Classes/filament/FilamentViewController.h index 36a33679..670e238b 100644 --- a/ios/Classes/filament/FilamentViewController.h +++ b/ios/Classes/filament/FilamentViewController.h @@ -18,14 +18,15 @@ #import "FilamentView.h" #import "Flutter/Flutter.h" +#import "FilamentViewer.hpp" @interface FilamentViewController : UIViewController @property(weak, nonatomic) IBOutlet FilamentView* modelView; - +- (void)setViewer:(mimetic::FilamentViewer*)viewer; - (void)startDisplayLink; - (void)stopDisplayLink; --initWithRegistrar:(NSObject*)registrar; +-initWithRegistrar:(NSObject*)registrar view:(FilamentView*)view; @end diff --git a/ios/Classes/filament/FilamentViewController.mm b/ios/Classes/filament/FilamentViewController.mm index 39d1e6d8..bb11b2c1 100644 --- a/ios/Classes/filament/FilamentViewController.mm +++ b/ios/Classes/filament/FilamentViewController.mm @@ -16,20 +16,29 @@ #import "FilamentViewController.h" #import "FilamentView.h" - +#import "FilamentViewer.hpp" #import @implementation FilamentViewController { CADisplayLink* _displayLink; NSObject* _registrar; + mimetic::FilamentViewer* _viewer; + FilamentView* _view; } -- (instancetype)initWithRegistrar:(NSObject*)registrar { +- (instancetype)initWithRegistrar:(NSObject*)registrar + view:(FilamentView*)view { if (self = [super init]) { _registrar = registrar; + _view = view; } + return self; } +- (void)setViewer:(mimetic::FilamentViewer*)viewer { + _viewer = viewer; + [_view setViewer:_viewer]; +} #pragma mark UIViewController methods - (void)viewDidLoad { @@ -58,8 +67,10 @@ _displayLink = nil; } -- (void)render { - +- (void)render { + if(_viewer) { + _viewer->render(); + } } - (void)dealloc { diff --git a/ios/mimetic_filament.podspec b/ios/mimetic_filament.podspec index cf2947e0..560819d9 100644 --- a/ios/mimetic_filament.podspec +++ b/ios/mimetic_filament.podspec @@ -20,11 +20,16 @@ A new flutter plugin project. s.static_framework = true # Flutter.framework does not contain a i386 slice. + s.xcconfig = { + 'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES', + 'ALWAYS_SEARCH_USER_PATHS' => 'YES', + 'USER_HEADER_SEARCH_PATHS' => '"${PODS_ROOT}/../.symlinks/plugins/mimetic_filament/ios/include" "${PODS_ROOT}/../.symlinks/plugins/mimetic_filament/ios/src"', + + } s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386', - 'ALWAYS_SEARCH_USER_PATHS' => 'YES', - 'USER_HEADER_SEARCH_PATHS' => '"${PODS_ROOT}/../.symlinks/plugins/mimetic_filament/ios/include"', - 'OTHER_CFLAGS' => '-fmodules -fcxx-modules' } + 'OTHER_CFLAGS' => '-fmodules -fcxx-modules' + } s.swift_version = '5.0' end diff --git a/ios/src/FilamentViewer.cpp b/ios/src/FilamentViewer.cpp index 40f6d90a..f7e13948 100644 --- a/ios/src/FilamentViewer.cpp +++ b/ios/src/FilamentViewer.cpp @@ -20,6 +20,7 @@ #include #include #include + #include #include #include @@ -28,6 +29,7 @@ #include #include #include +#include #include #include @@ -39,6 +41,7 @@ #include #include +#include #include #include @@ -47,6 +50,13 @@ #include +#include + +#include +#include + + + using namespace filament; using namespace filament::math; using namespace gltfio; @@ -97,7 +107,7 @@ FilamentViewer::FilamentViewer( _resourceLoader = new ResourceLoader( {.engine = _engine, .normalizeSkinningWeights = true, .recomputeBoundingBoxes = false}); - _manipulator = + manipulator = Manipulator::Builder().orbitHomePosition(0.0f, 0.0f, 0.0f).targetPosition(0.0f, 0.0f, 0).build(Mode::ORBIT); //Manipulator::Builder().orbitHomePosition(0.0f, 0.0f, 0.0f).targetPosition(0.0f, 0.0f, 0).build(Mode::ORBIT); _asset = nullptr; @@ -107,15 +117,15 @@ FilamentViewer::~FilamentViewer() { } -void FilamentViewer::loadResources() { +void FilamentViewer::loadResources(string relativeResourcePath) { const char* const* const resourceUris = _asset->getResourceUris(); const size_t resourceUriCount = _asset->getResourceUriCount(); for (size_t i = 0; i < resourceUriCount; i++) { - const char* const uri = resourceUris[i]; - ResourceBuffer buf = _loadResource(uri); + string uri = relativeResourcePath + string(resourceUris[i]); + ResourceBuffer buf = _loadResource(uri.c_str()); ResourceLoader::BufferDescriptor b( buf.data, buf.size, (ResourceLoader::BufferDescriptor::Callback)&_freeResource, nullptr); - _resourceLoader->addResourceData(uri, std::move(b)); + _resourceLoader->addResourceData(resourceUris[i], std::move(b)); } _resourceLoader->loadResources(_asset); @@ -133,7 +143,7 @@ void FilamentViewer::loadResources() { _scene->addEntities(_asset->getEntities(), _asset->getEntityCount()); }; -void FilamentViewer::loadGltf(const char* const uri) { +void FilamentViewer::loadGltf(const char* const uri, const char* const relativeResourcePath) { _resourceLoader->asyncCancelLoad(); _resourceLoader->evictResourceData(); if(_asset) { @@ -150,7 +160,13 @@ void FilamentViewer::loadGltf(const char* const uri) { exit(1); } - loadResources(); + loadResources(string(relativeResourcePath) + string("/")); + + _freeResource((void*)rbuf.data, rbuf.size, nullptr); + + transformToUnitCube(); + + startTime = std::chrono::high_resolution_clock::now(); } @@ -163,6 +179,7 @@ void FilamentViewer::loadSkybox(const char* const skyboxPath, const char* const _skyboxTexture = image::ktx::createTexture(_engine, skyboxBundle, false); _skybox = filament::Skybox::Builder().environment(_skyboxTexture).build(*_engine); _scene->setSkybox(_skybox); + _freeResource((void*)skyboxBuffer.data, skyboxBuffer.size, nullptr); // Load IBL. ResourceBuffer iblBuffer = _loadResource(iblPath); @@ -178,6 +195,8 @@ void FilamentViewer::loadSkybox(const char* const skyboxPath, const char* const .intensity(30000.0f) .build(*_engine); _scene->setIndirectLight(_indirectLight); + + _freeResource((void*)iblBuffer.data, iblBuffer.size, nullptr); // Always add a direct light source since it is required for shadowing. _sun = EntityManager::get().create(); @@ -190,6 +209,20 @@ void FilamentViewer::loadSkybox(const char* const skyboxPath, const char* const _scene->addEntity(_sun); } +void FilamentViewer::transformToUnitCube() { + if (!_asset) { + return; + } + auto& tm = _engine->getTransformManager(); + auto aabb = _asset->getBoundingBox(); + auto center = aabb.center(); + auto halfExtent = aabb.extent(); + auto maxExtent = max(halfExtent) * 2; + auto scaleFactor = 2.0f / maxExtent; + auto transform = math::mat4f::scaling(scaleFactor) * math::mat4f::translation(-center); + tm.setTransform(tm.getInstance(_asset->getRoot()), transform); +} + void FilamentViewer::cleanup() { _resourceLoader->asyncCancelLoad(); _assetLoader->destroyAsset(_asset); @@ -197,5 +230,47 @@ void FilamentViewer::cleanup() { AssetLoader::destroy(&_assetLoader); }; +void FilamentViewer::render() { + if (!_view || !_mainCamera || !manipulator) { + return; + } + // Extract the camera basis from the helper and push it to the Filament camera. + math::float3 eye, target, upward; + manipulator->getLookAt(&eye, &target, &upward); + //std::cout << "eye " << eye[0] << " " << eye[1] << " " << eye[2] << " " << target[0] << " " << target[1] << " " << target[2] << std::endl; + _mainCamera->lookAt(eye, target, upward); + + if(_animator) { + // typedef std::chrono::high_resolution_clock clock; + typedef std::chrono::duration duration; + duration dur = std::chrono::high_resolution_clock::now() - startTime; + if (_animator->getAnimationCount() > 0) { + _animator->applyAnimation(0, dur.count() / 1000); + } + _animator->updateBoneMatrices(); + } + + // Render the scene, unless the renderer wants to skip the frame. + if (_renderer->beginFrame(_swapChain)) { + _renderer->render(_view); + _renderer->endFrame(); + } +} + +void FilamentViewer::updateViewportAndCameraProjection(int width, int height, float contentScaleFactor) { + if (!_view || !_mainCamera || !manipulator) { + return; + } + + manipulator->setViewport(width, height); + + const uint32_t _width = width * contentScaleFactor; + const uint32_t _height = height * contentScaleFactor; + _view->setViewport({0, 0, _width, _height}); + + const double aspect = (double)width / height; + _mainCamera->setLensProjection(_cameraFocalLength, aspect, kNearPlane, kFarPlane); +} + } diff --git a/ios/src/FilamentViewer.hpp b/ios/src/FilamentViewer.hpp index d7adcb0f..810f2c27 100644 --- a/ios/src/FilamentViewer.hpp +++ b/ios/src/FilamentViewer.hpp @@ -1,3 +1,5 @@ +#pragma once + #include #include #include @@ -26,6 +28,7 @@ #include #include #include +#include using namespace std; using namespace filament; @@ -40,7 +43,7 @@ namespace mimetic { struct ResourceBuffer { ResourceBuffer(const void* data, const uint32_t size) : data(data), size(size) {}; const void* data; - const uint32_t size; + const uint64_t size; }; using LoadResource = std::function; @@ -50,14 +53,21 @@ namespace mimetic { public: FilamentViewer(void* layer, LoadResource loadResource, FreeResource freeResource); ~FilamentViewer(); - void loadGltf(const char* const uri); + void loadGltf(const char* const uri, const char* relativeResourcePath); void loadSkybox(const char* const skyboxUri, const char* const iblUri); + void updateViewportAndCameraProjection(int height, int width, float scaleFactor); + void render(); + Manipulator* manipulator; private: - void loadResources(); + void loadResources(std::string relativeResourcePath); + void transformToUnitCube(); void cleanup(); void* _layer; + LoadResource _loadResource; FreeResource _freeResource; + + std::chrono::high_resolution_clock::time_point startTime; Scene* _scene; View* _view; @@ -69,8 +79,6 @@ namespace mimetic { Animator* _animator; - Manipulator* _manipulator; - AssetLoader* _assetLoader; FilamentAsset* _asset = nullptr; NameComponentManager* _ncm; diff --git a/lib/filament_controller.dart b/lib/filament_controller.dart index 6135995d..50763c6a 100644 --- a/lib/filament_controller.dart +++ b/lib/filament_controller.dart @@ -5,6 +5,10 @@ abstract class FilamentController { Future initialize(); Future loadSkybox(String skyboxPath, String lightingPath); Future loadGlb(String path); + Future loadGltf(String path, String relativeResourcePath); + Future panStart(double x, double y); + Future panUpdate(double x, double y); + Future panEnd(); } class MimeticFilamentController extends FilamentController { @@ -23,11 +27,27 @@ class MimeticFilamentController extends FilamentController { } @override - Future loadSkybox(String path) { - throw Exception(); + Future loadSkybox(String skyboxPath, String lightingPath) async { + await _channel.invokeMethod("loadSkybox", [skyboxPath, lightingPath]); } Future loadGlb(String path) { throw Exception(); } + + Future loadGltf(String path, String relativeResourcePath) async { + await _channel.invokeMethod("loadGltf", [path, relativeResourcePath]); + } + + Future panStart(double x, double y) async { + await _channel.invokeMethod("panStart", [x.toInt(), y.toInt()]); + } + + Future panUpdate(double x, double y) async { + await _channel.invokeMethod("panUpdate", [x.toInt(), y.toInt()]); + } + + Future panEnd() async { + await _channel.invokeMethod("panEnd"); + } } diff --git a/pubspec.yaml b/pubspec.yaml index b8cc9294..d9227a03 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,6 +10,8 @@ environment: dependencies: flutter: sdk: flutter + ffi: + plugin_platform_interface: ^2.0.0 dev_dependencies: