Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core motion implementation for iPhone (Accelerometer/Gyro/Magnetometer support) #7127

Merged
merged 5 commits into from
Jan 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/os/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ void Input::_bind_methods() {
ClassDB::bind_method(_MD("get_joy_axis_index_from_string", "axis"), &Input::get_joy_axis_index_from_string);
ClassDB::bind_method(_MD("start_joy_vibration", "device", "weak_magnitude", "strong_magnitude", "duration"), &Input::start_joy_vibration, DEFVAL(0));
ClassDB::bind_method(_MD("stop_joy_vibration", "device"), &Input::stop_joy_vibration);
ClassDB::bind_method(_MD("get_gravity"),&Input::get_gravity);
ClassDB::bind_method(_MD("get_accelerometer"),&Input::get_accelerometer);
ClassDB::bind_method(_MD("get_magnetometer"),&Input::get_magnetometer);
ClassDB::bind_method(_MD("get_gyroscope"),&Input::get_gyroscope);
Expand Down
1 change: 1 addition & 0 deletions core/os/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class Input : public Object {

virtual void warp_mouse_pos(const Vector2& p_to)=0;

virtual Vector3 get_gravity() const=0;
virtual Vector3 get_accelerometer() const=0;
virtual Vector3 get_magnetometer() const=0;
virtual Vector3 get_gyroscope() const=0;
Expand Down
14 changes: 14 additions & 0 deletions main/input_default.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,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() const{

_THREAD_SAFE_METHOD_
return gravity;
}

Vector3 InputDefault::get_accelerometer() const{

_THREAD_SAFE_METHOD_
Expand Down Expand Up @@ -423,6 +429,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_
Expand Down
3 changes: 3 additions & 0 deletions main/input_default.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class InputDefault : public Input {
Set<int> joy_buttons_pressed;
Map<int,float> _joy_axis;
//Map<StringName,int> custom_action_press;
Vector3 gravity;
Vector3 accelerometer;
Vector3 magnetometer;
Vector3 gyroscope;
Expand Down Expand Up @@ -191,6 +192,7 @@ class InputDefault : public Input {
void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid = "");
void parse_joypad_mapping(String p_mapping, bool p_update_existing);

virtual Vector3 get_gravity() const;
virtual Vector3 get_accelerometer() const;
virtual Vector3 get_magnetometer() const;
virtual Vector3 get_gyroscope() const;
Expand All @@ -203,6 +205,7 @@ class InputDefault : public Input {


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);
Expand Down
8 changes: 5 additions & 3 deletions platform/iphone/app_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@
#import "gl_view.h"
#import "view_controller.h"

@interface AppDelegate : NSObject <UIApplicationDelegate, UIAccelerometerDelegate, GLViewDelegate> {
// 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 <CoreMotion/CoreMotion.h>

@interface AppDelegate : NSObject <UIApplicationDelegate, GLViewDelegate> {
//@property (strong, nonatomic) UIWindow *window;
ViewController* view_controller;
UIAccelerationValue accel[3];
UIAccelerationValue last_accel[3];
};

@property (strong, nonatomic) UIWindow *window;
Expand Down
83 changes: 81 additions & 2 deletions platform/iphone/app_delegate.mm
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ @implementation AppDelegate
extern int iphone_main(int, int, int, char**);
extern void iphone_finish();

CMMotionManager *motionManager;
bool motionInitialised;

static ViewController* mainViewController = nil;
+ (ViewController*) getViewController
{
Expand Down Expand Up @@ -193,9 +196,58 @@ - (void)drawView:(GLView*)view; {
}; break; // no fallthrough

default: {

if (OSIPhone::get_singleton()) {
OSIPhone::get_singleton()->update_accelerometer(accel[0], accel[1], accel[2]);
// 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();
};

Expand Down Expand Up @@ -253,11 +305,24 @@ - (void)applicationDidFinishLaunching:(UIApplication*)application {
[window makeKeyAndVisible];

//Configure and start accelerometer
/*
Old accelerometer approach deprecated since IOS 7.0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say go ahead and remove the obsolete code, I don't think Apple will be reintroducing obsoleted APIs in future iOS versions :)


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;
Expand Down Expand Up @@ -297,12 +362,23 @@ - (void)applicationDidFinishLaunching:(UIApplication*)application {
- (void)applicationWillTerminate:(UIApplication*)application {

printf("********************* will terminate\n");

if (motionInitialised) {
///@TODO is this the right place to clean this up?
[motionManager stopDeviceMotionUpdates];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation ;)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'll be fixed when I apply clang-format anyway, so let's merge :p

[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];
Expand Down Expand Up @@ -340,12 +416,15 @@ - (void) applicationDidBecomeActive:(UIApplication *)application
};
}

/*
Depricated since IOS 7.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
Expand Down
3 changes: 3 additions & 0 deletions platform/iphone/detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ def configure(env):
'-framework', 'CoreAudio',
'-framework', 'CoreGraphics',
'-framework', 'CoreMedia',
'-framework', 'CoreMotion',
'-framework', 'Foundation',
'-framework', 'Security',
'-framework', 'UIKit',
Expand All @@ -109,6 +110,7 @@ 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',
Expand All @@ -126,6 +128,7 @@ def configure(env):
'-framework', 'MediaPlayer',
'-framework', 'AVFoundation',
'-framework', 'CoreMedia',
'-framework', 'CoreMotion',
])

if env['game_center'] == 'yes':
Expand Down
13 changes: 12 additions & 1 deletion platform/iphone/os_iphone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,9 +323,14 @@ void OSIPhone::touches_cancelled() {

static const float ACCEL_RANGE = 1;

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) {

input->set_accelerometer(Vector3(p_x / (float)ACCEL_RANGE, p_y / (float)ACCEL_RANGE, -p_z / (float)ACCEL_RANGE));
// 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));

/*
if (p_x != last_accel.x) {
Expand Down Expand Up @@ -364,7 +369,13 @@ void OSIPhone::update_accelerometer(float p_x, float p_y, float p_z) {
*/
};

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() {

Expand Down
3 changes: 3 additions & 0 deletions platform/iphone/os_iphone.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,10 @@ class OSIPhone : public OS_Unix {

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();

Expand Down