tidy up method call handler and add example project with camera panning

This commit is contained in:
Nick Fisher
2021-09-16 17:33:24 +08:00
parent a0f877be48
commit 8288758e78
16 changed files with 363 additions and 141 deletions

View File

@@ -310,6 +310,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO; ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -324,6 +325,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 9.0; IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
STRIP_INSTALLED_PRODUCT = NO;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
@@ -337,6 +339,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = 873X6R39HP; DEVELOPMENT_TEAM = 873X6R39HP;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp; GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp;
@@ -345,8 +348,10 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.example.mimeticAvatarExample; PRODUCT_BUNDLE_IDENTIFIER = com.example.mimeticAvatarExample;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
STRIP_INSTALLED_PRODUCT = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
@@ -383,6 +388,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = NO;
DEBUG_INFORMATION_FORMAT = dwarf; DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
@@ -404,6 +410,7 @@
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos; SDKROOT = iphoneos;
STRIP_INSTALLED_PRODUCT = NO;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
}; };
name = Debug; name = Debug;
@@ -438,6 +445,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO; ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -452,6 +460,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 9.0; IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
STRIP_INSTALLED_PRODUCT = NO;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule; SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_OPTIMIZATION_LEVEL = "-O";
@@ -467,6 +476,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = 873X6R39HP; DEVELOPMENT_TEAM = 873X6R39HP;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp; GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp;
@@ -475,8 +485,10 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.example.mimeticAvatarExample; PRODUCT_BUNDLE_IDENTIFIER = com.example.mimeticAvatarExample;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
STRIP_INSTALLED_PRODUCT = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
@@ -491,6 +503,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = 873X6R39HP; DEVELOPMENT_TEAM = 873X6R39HP;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp; GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp;
@@ -499,8 +512,10 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.example.mimeticAvatarExample; PRODUCT_BUNDLE_IDENTIFIER = com.example.mimeticAvatarExample;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
STRIP_INSTALLED_PRODUCT = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";

View File

@@ -18,7 +18,6 @@ class MyApp extends StatefulWidget {
class _MyAppState extends State<MyApp> { class _MyAppState extends State<MyApp> {
final FilamentController _filamentController = MimeticFilamentController(); final FilamentController _filamentController = MimeticFilamentController();
String _platformVersion = 'Unknown';
@override @override
void initState() { void initState() {
@@ -32,23 +31,44 @@ class _MyAppState extends State<MyApp> {
appBar: AppBar( appBar: AppBar(
title: const Text('Plugin example app'), title: const Text('Plugin example app'),
), ),
body: Stack(children: [ body: GestureDetector(
FilamentWidget(controller: _filamentController), behavior: HitTestBehavior.opaque,
Column(children: [ onPanDown: (details) {
ElevatedButton( _filamentController.panStart(
child: Text("initialize"), details.localPosition.dx, details.localPosition.dy);
onPressed: () { },
_filamentController.initialize(); onPanUpdate: (details) {
}), print(details.localPosition.dx);
ElevatedButton( _filamentController.panUpdate(
child: Text("load asset"), details.localPosition.dx, details.localPosition.dy);
onPressed: () { },
_filamentController.loadSkybox( onPanEnd: (d) {
"assets/default_env/default_env_skybox.ktx", _filamentController.panEnd();
"assets/default_env/default_env_ibl.ktx"); },
}), 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");
}),
]),
])),
), ),
); );
} }

View File

@@ -39,16 +39,14 @@ dev_dependencies:
# The following section is specific to Flutter. # The following section is specific to Flutter.
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 uses-material-design: true
assets:
# To add assets to your application, add an assets section, like this: - assets/
# assets: - assets/default_env/
# - images/a_dot_burr.jpeg - assets/BusterDrone/
# - images/a_dot_ham.jpeg - assets/BusterDrone/textures/
- assets/FlightHelmet/
- assets/FlightHelmet/textures/
# An image asset can refer to one or more resolution-specific "variants", see # An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware. # https://flutter.dev/assets-and-images/#resolution-aware.

View File

@@ -0,0 +1,23 @@
#ifndef FilamentMethodCallHandler_h
#define FilamentMethodCallHandler_h
#endif /* FilamentNativeViewFactory_h */
#import <Flutter/Flutter.h>
#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<FlutterPluginRegistrar>*)registrar
viewId:(int64_t)viewId
layer:(void*)layer;
@end

View File

@@ -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<FlutterPluginRegistrar>* _registrar;
}
- (instancetype)initWithController:(FilamentViewController*)controller
registrar:(NSObject<FlutterPluginRegistrar>*)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

View File

@@ -3,17 +3,13 @@
#endif /* FilamentNativeViewFactory_h */ #endif /* FilamentNativeViewFactory_h */
#import <Flutter/Flutter.h> #import <Flutter/Flutter.h>
#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 <FlutterPlatformViewFactory> @interface FilamentNativeViewFactory : NSObject <FlutterPlatformViewFactory>
- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar; - (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar;
- (mimetic::ResourceBuffer)loadResource:(const char* const)path;
- (void)freeResource:(void*)mem size:(size_t)size misc:(void*)misc;
@end @end
@interface FilamentNativeView : NSObject <FlutterPlatformView> @interface FilamentNativeView : NSObject <FlutterPlatformView>

View File

@@ -1,18 +1,6 @@
#import "FilamentNativeViewFactory.h" #import "FilamentNativeViewFactory.h"
#import "FilamentViewController.h" #import "FilamentViewController.h"
#import "FilamentMethodCallHandler.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;
}
@implementation FilamentNativeViewFactory { @implementation FilamentNativeViewFactory {
NSObject<FlutterPluginRegistrar>* _registrar; NSObject<FlutterPluginRegistrar>* _registrar;
@@ -23,7 +11,6 @@ static void* freeResource(void* mem, size_t size, void* misc) {
if (self) { if (self) {
_registrar = registrar; _registrar = registrar;
} }
_factory = self;
return self; return self;
} }
@@ -38,81 +25,27 @@ static void* freeResource(void* mem, size_t size, void* misc) {
@end @end
@implementation FilamentMethodCallHandler {
FilamentViewController *_controller;
FlutterMethodChannel* _channel;
mimetic::FilamentViewer* _viewer;
void* _layer;
}
- (instancetype)initWithController:(FilamentViewController*)controller
registrar:(NSObject<FlutterPluginRegistrar>*)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 { @implementation FilamentNativeView {
FilamentView *_view; FilamentView* _view;
FilamentViewController *_controller; FilamentViewController* _controller;
FilamentMethodCallHandler *_handler; mimetic::FilamentViewer* _viewer;
FilamentMethodCallHandler* _handler;
void* _layer;
} }
- (instancetype)initWithFrame:(CGRect)frame - (instancetype)initWithFrame:(CGRect)frame
viewIdentifier:(int64_t)viewId viewIdentifier:(int64_t)viewId
arguments:(id _Nullable)args arguments:(id _Nullable)args
registrar:(NSObject<FlutterPluginRegistrar>*)registrar { registrar:(NSObject<FlutterPluginRegistrar>*)registrar {
if (self = [super init]) { if (self = [super init]) {
_view = [[FilamentView alloc] init]; _view = [[FilamentView alloc] init];
_controller = [[FilamentViewController alloc] initWithRegistrar:registrar]; _controller = [[FilamentViewController alloc] initWithRegistrar:registrar view:_view];
_controller.modelView = _view;
[_controller viewDidLoad]; [_controller viewDidLoad];
[_controller startDisplayLink]; _layer = (__bridge_retained void*)[_view layer];
_handler = [[FilamentMethodCallHandler alloc] initWithController:_controller registrar:registrar viewId:viewId layer:(__bridge void*)[_view layer]]; _handler = [[FilamentMethodCallHandler alloc] initWithController:_controller registrar:registrar viewId:viewId layer:_layer];
} }
return self; return self;
} }

View File

@@ -15,7 +15,7 @@
*/ */
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#include "FilamentViewer.hpp"
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
/** /**
@@ -24,8 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
* *
*/ */
@interface FilamentView : UIView @interface FilamentView : UIView
- (void)setViewer:(mimetic::FilamentViewer*)viewer;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@@ -16,21 +16,26 @@
// These defines are set in the "Preprocessor Macros" build setting for each scheme. // These defines are set in the "Preprocessor Macros" build setting for each scheme.
#include "FilamentView.h" #include "FilamentView.h"
#include "FilamentViewer.hpp"
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
using namespace std; using namespace std;
@interface FilamentView () @interface FilamentView ()
- (void)initCommon; - (void)initCommon;
- (void)setViewer:(mimetic::FilamentViewer*)viewer;
@end @end
@implementation FilamentView { @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 { - (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) { if (self = [super initWithFrame:frame]) {
[self initCommon]; [self initCommon];
@@ -58,4 +63,18 @@ using namespace std;
return [CAEAGLLayer class]; 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 @end

View File

@@ -18,14 +18,15 @@
#import "FilamentView.h" #import "FilamentView.h"
#import "Flutter/Flutter.h" #import "Flutter/Flutter.h"
#import "FilamentViewer.hpp"
@interface FilamentViewController : UIViewController @interface FilamentViewController : UIViewController
@property(weak, nonatomic) IBOutlet FilamentView* modelView; @property(weak, nonatomic) IBOutlet FilamentView* modelView;
- (void)setViewer:(mimetic::FilamentViewer*)viewer;
- (void)startDisplayLink; - (void)startDisplayLink;
- (void)stopDisplayLink; - (void)stopDisplayLink;
-initWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar; -initWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar view:(FilamentView*)view;
@end @end

View File

@@ -16,20 +16,29 @@
#import "FilamentViewController.h" #import "FilamentViewController.h"
#import "FilamentView.h" #import "FilamentView.h"
#import "FilamentViewer.hpp"
#import <Flutter/Flutter.h> #import <Flutter/Flutter.h>
@implementation FilamentViewController { @implementation FilamentViewController {
CADisplayLink* _displayLink; CADisplayLink* _displayLink;
NSObject<FlutterPluginRegistrar>* _registrar; NSObject<FlutterPluginRegistrar>* _registrar;
mimetic::FilamentViewer* _viewer;
FilamentView* _view;
} }
- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar { - (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar
view:(FilamentView*)view {
if (self = [super init]) { if (self = [super init]) {
_registrar = registrar; _registrar = registrar;
_view = view;
} }
return self; return self;
} }
- (void)setViewer:(mimetic::FilamentViewer*)viewer {
_viewer = viewer;
[_view setViewer:_viewer];
}
#pragma mark UIViewController methods #pragma mark UIViewController methods
- (void)viewDidLoad { - (void)viewDidLoad {
@@ -59,7 +68,9 @@
} }
- (void)render { - (void)render {
if(_viewer) {
_viewer->render();
}
} }
- (void)dealloc { - (void)dealloc {

View File

@@ -20,11 +20,16 @@ A new flutter plugin project.
s.static_framework = true s.static_framework = true
# Flutter.framework does not contain a i386 slice. # 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 = { s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES', 'DEFINES_MODULE' => 'YES',
'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386',
'ALWAYS_SEARCH_USER_PATHS' => 'YES', 'OTHER_CFLAGS' => '-fmodules -fcxx-modules'
'USER_HEADER_SEARCH_PATHS' => '"${PODS_ROOT}/../.symlinks/plugins/mimetic_filament/ios/include"', }
'OTHER_CFLAGS' => '-fmodules -fcxx-modules' }
s.swift_version = '5.0' s.swift_version = '5.0'
end end

View File

@@ -20,6 +20,7 @@
#include <filament/Camera.h> #include <filament/Camera.h>
#include <filament/ColorGrading.h> #include <filament/ColorGrading.h>
#include <filament/Engine.h> #include <filament/Engine.h>
#include <filament/IndexBuffer.h> #include <filament/IndexBuffer.h>
#include <filament/RenderableManager.h> #include <filament/RenderableManager.h>
#include <filament/Renderer.h> #include <filament/Renderer.h>
@@ -28,6 +29,7 @@
#include <filament/TransformManager.h> #include <filament/TransformManager.h>
#include <filament/VertexBuffer.h> #include <filament/VertexBuffer.h>
#include <filament/View.h> #include <filament/View.h>
#include <filament/Viewport.h>
#include <filament/IndirectLight.h> #include <filament/IndirectLight.h>
#include <filament/LightManager.h> #include <filament/LightManager.h>
@@ -39,6 +41,7 @@
#include <camutils/Manipulator.h> #include <camutils/Manipulator.h>
#include <utils/NameComponentManager.h> #include <utils/NameComponentManager.h>
#include <utils/JobSystem.h>
#include <math/vec3.h> #include <math/vec3.h>
#include <math/vec4.h> #include <math/vec4.h>
@@ -47,6 +50,13 @@
#include <image/KtxUtility.h> #include <image/KtxUtility.h>
#include <gltfio/Animator.h>
#include <chrono>
#include <iostream>
using namespace filament; using namespace filament;
using namespace filament::math; using namespace filament::math;
using namespace gltfio; using namespace gltfio;
@@ -97,7 +107,7 @@ FilamentViewer::FilamentViewer(
_resourceLoader = new ResourceLoader( _resourceLoader = new ResourceLoader(
{.engine = _engine, .normalizeSkinningWeights = true, .recomputeBoundingBoxes = false}); {.engine = _engine, .normalizeSkinningWeights = true, .recomputeBoundingBoxes = false});
_manipulator = manipulator =
Manipulator<float>::Builder().orbitHomePosition(0.0f, 0.0f, 0.0f).targetPosition(0.0f, 0.0f, 0).build(Mode::ORBIT); Manipulator<float>::Builder().orbitHomePosition(0.0f, 0.0f, 0.0f).targetPosition(0.0f, 0.0f, 0).build(Mode::ORBIT);
//Manipulator<float>::Builder().orbitHomePosition(0.0f, 0.0f, 0.0f).targetPosition(0.0f, 0.0f, 0).build(Mode::ORBIT); //Manipulator<float>::Builder().orbitHomePosition(0.0f, 0.0f, 0.0f).targetPosition(0.0f, 0.0f, 0).build(Mode::ORBIT);
_asset = nullptr; _asset = nullptr;
@@ -107,15 +117,15 @@ FilamentViewer::~FilamentViewer() {
} }
void FilamentViewer::loadResources() { void FilamentViewer::loadResources(string relativeResourcePath) {
const char* const* const resourceUris = _asset->getResourceUris(); const char* const* const resourceUris = _asset->getResourceUris();
const size_t resourceUriCount = _asset->getResourceUriCount(); const size_t resourceUriCount = _asset->getResourceUriCount();
for (size_t i = 0; i < resourceUriCount; i++) { for (size_t i = 0; i < resourceUriCount; i++) {
const char* const uri = resourceUris[i]; string uri = relativeResourcePath + string(resourceUris[i]);
ResourceBuffer buf = _loadResource(uri); ResourceBuffer buf = _loadResource(uri.c_str());
ResourceLoader::BufferDescriptor b( ResourceLoader::BufferDescriptor b(
buf.data, buf.size, (ResourceLoader::BufferDescriptor::Callback)&_freeResource, nullptr); 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); _resourceLoader->loadResources(_asset);
@@ -133,7 +143,7 @@ void FilamentViewer::loadResources() {
_scene->addEntities(_asset->getEntities(), _asset->getEntityCount()); _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->asyncCancelLoad();
_resourceLoader->evictResourceData(); _resourceLoader->evictResourceData();
if(_asset) { if(_asset) {
@@ -150,7 +160,13 @@ void FilamentViewer::loadGltf(const char* const uri) {
exit(1); 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); _skyboxTexture = image::ktx::createTexture(_engine, skyboxBundle, false);
_skybox = filament::Skybox::Builder().environment(_skyboxTexture).build(*_engine); _skybox = filament::Skybox::Builder().environment(_skyboxTexture).build(*_engine);
_scene->setSkybox(_skybox); _scene->setSkybox(_skybox);
_freeResource((void*)skyboxBuffer.data, skyboxBuffer.size, nullptr);
// Load IBL. // Load IBL.
ResourceBuffer iblBuffer = _loadResource(iblPath); ResourceBuffer iblBuffer = _loadResource(iblPath);
@@ -179,6 +196,8 @@ void FilamentViewer::loadSkybox(const char* const skyboxPath, const char* const
.build(*_engine); .build(*_engine);
_scene->setIndirectLight(_indirectLight); _scene->setIndirectLight(_indirectLight);
_freeResource((void*)iblBuffer.data, iblBuffer.size, nullptr);
// Always add a direct light source since it is required for shadowing. // Always add a direct light source since it is required for shadowing.
_sun = EntityManager::get().create(); _sun = EntityManager::get().create();
LightManager::Builder(LightManager::Type::DIRECTIONAL) LightManager::Builder(LightManager::Type::DIRECTIONAL)
@@ -190,6 +209,20 @@ void FilamentViewer::loadSkybox(const char* const skyboxPath, const char* const
_scene->addEntity(_sun); _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() { void FilamentViewer::cleanup() {
_resourceLoader->asyncCancelLoad(); _resourceLoader->asyncCancelLoad();
_assetLoader->destroyAsset(_asset); _assetLoader->destroyAsset(_asset);
@@ -197,5 +230,47 @@ void FilamentViewer::cleanup() {
AssetLoader::destroy(&_assetLoader); 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<float, std::milli> 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);
}
} }

View File

@@ -1,3 +1,5 @@
#pragma once
#include <filament/Camera.h> #include <filament/Camera.h>
#include <filament/ColorGrading.h> #include <filament/ColorGrading.h>
#include <filament/Engine.h> #include <filament/Engine.h>
@@ -26,6 +28,7 @@
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <chrono>
using namespace std; using namespace std;
using namespace filament; using namespace filament;
@@ -40,7 +43,7 @@ namespace mimetic {
struct ResourceBuffer { struct ResourceBuffer {
ResourceBuffer(const void* data, const uint32_t size) : data(data), size(size) {}; ResourceBuffer(const void* data, const uint32_t size) : data(data), size(size) {};
const void* data; const void* data;
const uint32_t size; const uint64_t size;
}; };
using LoadResource = std::function<ResourceBuffer(const char* uri)>; using LoadResource = std::function<ResourceBuffer(const char* uri)>;
@@ -50,15 +53,22 @@ namespace mimetic {
public: public:
FilamentViewer(void* layer, LoadResource loadResource, FreeResource freeResource); FilamentViewer(void* layer, LoadResource loadResource, FreeResource freeResource);
~FilamentViewer(); ~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 loadSkybox(const char* const skyboxUri, const char* const iblUri);
void updateViewportAndCameraProjection(int height, int width, float scaleFactor);
void render();
Manipulator<float>* manipulator;
private: private:
void loadResources(); void loadResources(std::string relativeResourcePath);
void transformToUnitCube();
void cleanup(); void cleanup();
void* _layer; void* _layer;
LoadResource _loadResource; LoadResource _loadResource;
FreeResource _freeResource; FreeResource _freeResource;
std::chrono::high_resolution_clock::time_point startTime;
Scene* _scene; Scene* _scene;
View* _view; View* _view;
Engine* _engine; Engine* _engine;
@@ -69,8 +79,6 @@ namespace mimetic {
Animator* _animator; Animator* _animator;
Manipulator<float>* _manipulator;
AssetLoader* _assetLoader; AssetLoader* _assetLoader;
FilamentAsset* _asset = nullptr; FilamentAsset* _asset = nullptr;
NameComponentManager* _ncm; NameComponentManager* _ncm;

View File

@@ -5,6 +5,10 @@ abstract class FilamentController {
Future initialize(); Future initialize();
Future loadSkybox(String skyboxPath, String lightingPath); Future loadSkybox(String skyboxPath, String lightingPath);
Future loadGlb(String path); 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 { class MimeticFilamentController extends FilamentController {
@@ -23,11 +27,27 @@ class MimeticFilamentController extends FilamentController {
} }
@override @override
Future loadSkybox(String path) { Future loadSkybox(String skyboxPath, String lightingPath) async {
throw Exception(); await _channel.invokeMethod("loadSkybox", [skyboxPath, lightingPath]);
} }
Future loadGlb(String path) { Future loadGlb(String path) {
throw Exception(); 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");
}
} }

View File

@@ -10,6 +10,8 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
ffi:
plugin_platform_interface: ^2.0.0 plugin_platform_interface: ^2.0.0
dev_dependencies: dev_dependencies: