diff --git a/core/os/input.cpp b/core/os/input.cpp index 3ccb57cd4ff..07d351e91fb 100644 --- a/core/os/input.cpp +++ b/core/os/input.cpp @@ -68,6 +68,7 @@ void Input::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_joy_axis_index_from_string", "axis"), &Input::get_joy_axis_index_from_string); ObjectTypeDB::bind_method(_MD("start_joy_vibration", "device", "weak_magnitude", "strong_magnitude", "duration"), &Input::start_joy_vibration, DEFVAL(0)); ObjectTypeDB::bind_method(_MD("stop_joy_vibration", "device"), &Input::stop_joy_vibration); + ObjectTypeDB::bind_method(_MD("get_gravity"),&Input::get_gravity); ObjectTypeDB::bind_method(_MD("get_accelerometer"),&Input::get_accelerometer); ObjectTypeDB::bind_method(_MD("get_magnetometer"),&Input::get_magnetometer); ObjectTypeDB::bind_method(_MD("get_gyroscope"),&Input::get_gyroscope); diff --git a/core/os/input.h b/core/os/input.h index 582729a7801..aaea50b78bc 100644 --- a/core/os/input.h +++ b/core/os/input.h @@ -80,6 +80,7 @@ public: virtual void warp_mouse_pos(const Vector2& p_to)=0; + virtual Vector3 get_gravity()=0; virtual Vector3 get_accelerometer()=0; virtual Vector3 get_magnetometer()=0; virtual Vector3 get_gyroscope()=0; diff --git a/main/input_default.cpp b/main/input_default.cpp index 90d23b0c142..78362f54f48 100644 --- a/main/input_default.cpp +++ b/main/input_default.cpp @@ -247,6 +247,12 @@ void InputDefault::joy_connection_changed(int p_idx, bool p_connected, String p_ emit_signal("joy_connection_changed", p_idx, p_connected); }; +Vector3 InputDefault::get_gravity() { + + _THREAD_SAFE_METHOD_ + return gravity; +} + Vector3 InputDefault::get_accelerometer() { _THREAD_SAFE_METHOD_ @@ -376,6 +382,14 @@ void InputDefault::stop_joy_vibration(int p_device) { joy_vibration[p_device] = vibration; } +void InputDefault::set_gravity(const Vector3& p_gravity) { + + _THREAD_SAFE_METHOD_ + + gravity=p_gravity; + +} + void InputDefault::set_accelerometer(const Vector3& p_accel) { _THREAD_SAFE_METHOD_ diff --git a/main/input_default.h b/main/input_default.h index cb9668f9682..ebf4ad7a680 100644 --- a/main/input_default.h +++ b/main/input_default.h @@ -42,6 +42,7 @@ class InputDefault : public Input { Set joy_buttons_pressed; Map _joy_axis; Map custom_action_press; + Vector3 gravity; Vector3 accelerometer; Vector3 magnetometer; Vector3 gyroscope; @@ -178,6 +179,7 @@ public: void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid = ""); void parse_joystick_mapping(String p_mapping, bool p_update_existing); + virtual Vector3 get_gravity(); virtual Vector3 get_accelerometer(); virtual Vector3 get_magnetometer(); virtual Vector3 get_gyroscope(); @@ -190,6 +192,7 @@ public: void parse_input_event(const InputEvent& p_event); + void set_gravity(const Vector3& p_gravity); void set_accelerometer(const Vector3& p_accel); void set_magnetometer(const Vector3& p_magnetometer); void set_gyroscope(const Vector3& p_gyroscope); diff --git a/platform/iphone/app_delegate.h b/platform/iphone/app_delegate.h index 09c401b3295..6883692b156 100644 --- a/platform/iphone/app_delegate.h +++ b/platform/iphone/app_delegate.h @@ -30,11 +30,13 @@ #import "gl_view.h" #import "view_controller.h" -@interface AppDelegate : NSObject { +// Old accelerometer approach deprecated since IOS 7.0 +// Include coremotion for accelerometer, gyroscope and magnetometer access, available since IOS 4.0 but some functionality won't work for anything before IOS 5.0 +#import + +@interface AppDelegate : NSObject { //@property (strong, nonatomic) UIWindow *window; ViewController* view_controller; - UIAccelerationValue accel[3]; - UIAccelerationValue last_accel[3]; }; @property (strong, nonatomic) UIWindow *window; diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm index 86c3eecd47c..9900d0e6790 100644 --- a/platform/iphone/app_delegate.mm +++ b/platform/iphone/app_delegate.mm @@ -84,6 +84,9 @@ extern char** gargv; extern int iphone_main(int, int, int, char**); extern void iphone_finish(); +CMMotionManager *motionManager; +bool motionInitialised; + static ViewController* mainViewController = nil; + (ViewController*) getViewController { @@ -195,7 +198,56 @@ static int frame_count = 0; default: { if (OSIPhone::get_singleton()) { - OSIPhone::get_singleton()->update_accelerometer(accel[0], accel[1], accel[2]); + if (motionInitialised) { + // Just using polling approach for now, we can set this up so it sends data to us in intervals, might be better. + // See Apple reference pages for more details: + // https://developer.apple.com/reference/coremotion/cmmotionmanager?language=objc + + // Apple splits our accelerometer date into a gravity and user movement component. We add them back together + CMAcceleration gravity = motionManager.deviceMotion.gravity; + CMAcceleration acceleration = motionManager.deviceMotion.userAcceleration; + + ///@TODO We don't seem to be getting data here, is my device broken or is this code incorrect? + CMMagneticField magnetic = motionManager.deviceMotion.magneticField.field; + + ///@TODO we can access rotationRate as a CMRotationRate variable (processed date) or CMGyroData (raw data), have to see what works best + CMRotationRate rotation = motionManager.deviceMotion.rotationRate; + + // Adjust for screen orientation. + // [[UIDevice currentDevice] orientation] changes even if we've fixed our orientation which is not + // a good thing when you're trying to get your user to move the screen in all directions and want consistent output + + ///@TODO Using [[UIApplication sharedApplication] statusBarOrientation] is a bit of a hack. Godot obviously knows the orientation so maybe we + // can use that instead? (note that left and right seem swapped) + + switch ([[UIApplication sharedApplication] statusBarOrientation]) { + case UIDeviceOrientationLandscapeLeft: { + OSIPhone::get_singleton()->update_gravity(-gravity.y, gravity.x, gravity.z); + OSIPhone::get_singleton()->update_accelerometer(-(acceleration.y + gravity.y), (acceleration.x + gravity.x), acceleration.z + gravity.z); + OSIPhone::get_singleton()->update_magnetometer(-magnetic.y, magnetic.x, magnetic.z); + OSIPhone::get_singleton()->update_gyroscope(-rotation.y, rotation.x, rotation.z); + }; break; + case UIDeviceOrientationLandscapeRight: { + OSIPhone::get_singleton()->update_gravity(gravity.y, -gravity.x, gravity.z); + OSIPhone::get_singleton()->update_accelerometer((acceleration.y + gravity.y), -(acceleration.x + gravity.x), acceleration.z + gravity.z); + OSIPhone::get_singleton()->update_magnetometer(magnetic.y, -magnetic.x, magnetic.z); + OSIPhone::get_singleton()->update_gyroscope(rotation.y, -rotation.x, rotation.z); + }; break; + case UIDeviceOrientationPortraitUpsideDown: { + OSIPhone::get_singleton()->update_gravity(-gravity.x, gravity.y, gravity.z); + OSIPhone::get_singleton()->update_accelerometer(-(acceleration.x + gravity.x), (acceleration.y + gravity.y), acceleration.z + gravity.z); + OSIPhone::get_singleton()->update_magnetometer(-magnetic.x, magnetic.y, magnetic.z); + OSIPhone::get_singleton()->update_gyroscope(-rotation.x, rotation.y, rotation.z); + }; break; + default: { // assume portrait + OSIPhone::get_singleton()->update_gravity(gravity.x, gravity.y, gravity.z); + OSIPhone::get_singleton()->update_accelerometer(acceleration.x + gravity.x, acceleration.y + gravity.y, acceleration.z + gravity.z); + OSIPhone::get_singleton()->update_magnetometer(magnetic.x, magnetic.y, magnetic.z); + OSIPhone::get_singleton()->update_gyroscope(rotation.x, rotation.y, rotation.z); + }; break; + }; + } + bool quit_request = OSIPhone::get_singleton()->iterate(); }; @@ -252,12 +304,14 @@ static int frame_count = 0; //Show the window [window makeKeyAndVisible]; - //Configure and start accelerometer - last_accel[0] = 0; - last_accel[1] = 0; - last_accel[2] = 0; - [[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / kAccelerometerFrequency)]; - [[UIAccelerometer sharedAccelerometer] setDelegate:self]; + if (!motionInitialised) { + motionManager = [[CMMotionManager alloc] init]; + if (motionManager.deviceMotionAvailable) { + motionManager.deviceMotionUpdateInterval = 1.0/70.0; + [motionManager startDeviceMotionUpdates]; + motionInitialised = YES; + }; + }; //OSIPhone::screen_width = rect.size.width - rect.origin.x; //OSIPhone::screen_height = rect.size.height - rect.origin.y; @@ -297,12 +351,23 @@ static int frame_count = 0; - (void)applicationWillTerminate:(UIApplication*)application { printf("********************* will terminate\n"); + + if (motionInitialised) { + ///@TODO is this the right place to clean this up? + [motionManager stopDeviceMotionUpdates]; + [motionManager release]; + motionManager = nil; + motionInitialised = NO; + }; + iphone_finish(); }; - (void)applicationDidEnterBackground:(UIApplication *)application { printf("********************* did enter background\n"); + ///@TODO maybe add pause motionManager? and where would we unpause it? + if (OS::get_singleton()->get_main_loop()) OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT); [view_controller.view stopAnimation]; @@ -340,13 +405,6 @@ static int frame_count = 0; }; } -- (void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration { - //Use a basic low-pass filter to only keep the gravity in the accelerometer values - accel[0] = acceleration.x; // * kFilteringFactor + accel[0] * (1.0 - kFilteringFactor); - accel[1] = acceleration.y; // * kFilteringFactor + accel[1] * (1.0 - kFilteringFactor); - accel[2] = acceleration.z; // * kFilteringFactor + accel[2] * (1.0 - kFilteringFactor); -} - - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url { #ifdef MODULE_FACEBOOKSCORER_IOS_ENABLED return [[[FacebookScorer sharedInstance] facebook] handleOpenURL:url]; diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py index b92b64e9f11..b20b9244b7d 100644 --- a/platform/iphone/detect.py +++ b/platform/iphone/detect.py @@ -62,13 +62,13 @@ def configure(env): env['CCFLAGS'] = string.split('-arch i386 -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fasm-blocks -Wall -D__IPHONE_OS_VERSION_MIN_REQUIRED=40100 -isysroot $IPHONESDK -mios-simulator-version-min=4.3 -DCUSTOM_MATRIX_TRANSFORM_H=\\\"build/iphone/matrix4_iphone.h\\\" -DCUSTOM_VECTOR3_TRANSFORM_H=\\\"build/iphone/vector3_iphone.h\\\"') elif (env["arch"] == "arm64"): # arm64 env["bits"] = "64" - env['CCFLAGS'] = string.split('-fno-objc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -Wno-trigraphs -fpascal-strings -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -fvisibility=hidden -Wno-sign-conversion -MMD -MT dependencies -miphoneos-version-min=5.1.1 -isysroot $IPHONESDK') + env['CCFLAGS'] = string.split('-fno-objc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -Wno-trigraphs -fpascal-strings -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -fvisibility=hidden -Wno-sign-conversion -MMD -MT dependencies -miphoneos-version-min=7.0 -isysroot $IPHONESDK') env.Append(CPPFLAGS=['-DNEED_LONG_INT']) env.Append(CPPFLAGS=['-DLIBYUV_DISABLE_NEON']) else: # armv7 env["arch"] = "arm" env["bits"] = "32" - env['CCFLAGS'] = string.split('-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -Wno-trigraphs -fpascal-strings -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk -fvisibility=hidden -Wno-sign-conversion -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=5.1.1 -MMD -MT dependencies -isysroot $IPHONESDK') + env['CCFLAGS'] = string.split('-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -Wno-trigraphs -fpascal-strings -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk -fvisibility=hidden -Wno-sign-conversion -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=7.0 -MMD -MT dependencies -isysroot $IPHONESDK') if (env["arch"] == "x86"): env['IPHONEPLATFORM'] = 'iPhoneSimulator' @@ -83,6 +83,7 @@ def configure(env): '-framework', 'CoreAudio', '-framework', 'CoreGraphics', '-framework', 'CoreMedia', + '-framework', 'CoreMotion', '-framework', 'Foundation', '-framework', 'Security', '-framework', 'UIKit', @@ -93,7 +94,7 @@ def configure(env): '-F$IPHONESDK', ]) elif (env["arch"] == "arm64"): - env.Append(LINKFLAGS=['-arch', 'arm64', '-Wl,-dead_strip', '-miphoneos-version-min=5.1.1', + env.Append(LINKFLAGS=['-arch', 'arm64', '-Wl,-dead_strip', '-miphoneos-version-min=7.0', '-isysroot', '$IPHONESDK', #'-stdlib=libc++', '-framework', 'Foundation', @@ -109,9 +110,10 @@ def configure(env): '-framework', 'MediaPlayer', '-framework', 'AVFoundation', '-framework', 'CoreMedia', + '-framework', 'CoreMotion', ]) else: - env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=5.1.1', + env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=7.0', '-isysroot', '$IPHONESDK', '-framework', 'Foundation', '-framework', 'UIKit', @@ -126,6 +128,7 @@ def configure(env): '-framework', 'MediaPlayer', '-framework', 'AVFoundation', '-framework', 'CoreMedia', + '-framework', 'CoreMotion', ]) if env['game_center'] == 'yes': diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp index e4d99cc5028..c7eef6d3359 100644 --- a/platform/iphone/os_iphone.cpp +++ b/platform/iphone/os_iphone.cpp @@ -323,48 +323,24 @@ void OSIPhone::touches_cancelled() { static const float ACCEL_RANGE = 1; -void OSIPhone::update_accelerometer(float p_x, float p_y, float p_z) { - - input->set_accelerometer(Vector3(p_x / (float)ACCEL_RANGE, p_y / (float)ACCEL_RANGE, -p_z / (float)ACCEL_RANGE)); - - /* - if (p_x != last_accel.x) { - //printf("updating accel x %f\n", p_x); - InputEvent ev; - ev.type = InputEvent::JOYSTICK_MOTION; - ev.device = 0; - ev.joy_motion.axis = JOY_ANALOG_0_X; - ev.joy_motion.axis_value = (p_x / (float)ACCEL_RANGE); - ev.ID = ++last_event_id; - last_accel.x = p_x; - queue_event(ev); - }; - if (p_y != last_accel.y) { - //printf("updating accel y %f\n", p_y); - InputEvent ev; - ev.type = InputEvent::JOYSTICK_MOTION; - ev.device = 0; - ev.joy_motion.axis = JOY_ANALOG_0_Y; - ev.joy_motion.axis_value = (p_y / (float)ACCEL_RANGE); - ev.ID = ++last_event_id; - last_accel.y = p_y; - queue_event(ev); - }; - if (p_z != last_accel.z) { - //printf("updating accel z %f\n", p_z); - InputEvent ev; - ev.type = InputEvent::JOYSTICK_MOTION; - ev.device = 0; - ev.joy_motion.axis = JOY_ANALOG_1_X; - ev.joy_motion.axis_value = ( (1.0 - p_z) / (float)ACCEL_RANGE); - ev.ID = ++last_event_id; - last_accel.z = p_z; - queue_event(ev); - }; - */ +void OSIPhone::update_gravity(float p_x, float p_y, float p_z) { + input->set_gravity(Vector3(p_x, p_y, p_z)); }; +void OSIPhone::update_accelerometer(float p_x, float p_y, float p_z) { + // Found out the Z should not be negated! Pass as is! + input->set_accelerometer(Vector3(p_x / (float)ACCEL_RANGE, p_y / (float)ACCEL_RANGE, p_z / (float)ACCEL_RANGE)); + +}; + +void OSIPhone::update_magnetometer(float p_x, float p_y, float p_z) { + input->set_magnetometer(Vector3(p_x, p_y, p_z)); +}; + +void OSIPhone::update_gyroscope(float p_x, float p_y, float p_z) { + input->set_gyroscope(Vector3(p_x, p_y, p_z)); +}; void OSIPhone::delete_main_loop() { diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h index 331b20afbfc..ab976edcba6 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -152,7 +152,10 @@ public: int set_base_framebuffer(int p_fb); + void update_gravity(float p_x, float p_y, float p_z); void update_accelerometer(float p_x, float p_y, float p_z); + void update_magnetometer(float p_x, float p_y, float p_z); + void update_gyroscope(float p_x, float p_y, float p_z); static OSIPhone* get_singleton();