Skip to content

Commit

Permalink
Update the existing haptic player when we rumble on iOS
Browse files Browse the repository at this point in the history
  • Loading branch information
slouken committed Oct 15, 2020
1 parent 645a328 commit d9aea0c
Showing 1 changed file with 94 additions and 68 deletions.
162 changes: 94 additions & 68 deletions src/joystick/iphoneos/SDL_sysjoystick.m
Expand Up @@ -827,6 +827,7 @@ @interface SDL_RumbleMotor : NSObject
@implementation SDL_RumbleMotor {
CHHapticEngine *engine API_AVAILABLE(ios(13.0), tvos(14.0));
id<CHHapticPatternPlayer> player API_AVAILABLE(ios(13.0), tvos(14.0));
bool active;
}

-(void)cleanup
Expand All @@ -843,78 +844,92 @@ -(void)cleanup

-(int)setIntensity:(float)intensity
{
if (@available(iOS 14.0, tvOS 14.0, *)) {
NSError *error;

if (self->player != nil) {
[self->player stopAtTime:0 error:&error];
self->player = nil;
}

if (self->engine == nil) {
return SDL_SetError("Haptics engine not available");
}

if (intensity <= 0.01f) {
return 0;
}

CHHapticEventParameter *param = [[CHHapticEventParameter alloc] initWithParameterID:CHHapticEventParameterIDHapticIntensity value:intensity];
CHHapticEvent *event = [[CHHapticEvent alloc] initWithEventType:CHHapticEventTypeHapticContinuous parameters:[NSArray arrayWithObjects:param, nil] relativeTime:0 duration:GCHapticDurationInfinite];
CHHapticPattern *pattern = [[CHHapticPattern alloc] initWithEvents:[NSArray arrayWithObject:event] parameters:[[NSArray alloc] init] error:&error];
if (error != nil) {
return SDL_SetError("Couldn't create haptic pattern: %s", [error.localizedDescription UTF8String]);
}

self->player = [self->engine createPlayerWithPattern:pattern error:&error];
if (error != nil) {
return SDL_SetError("Couldn't create haptic player: %s", [error.localizedDescription UTF8String]);
}

[self->player startAtTime:0 error:&error];
if (error != nil) {
self->player = nil;
return SDL_SetError("Couldn't start playback: %s", [error.localizedDescription UTF8String]);
}
}
return 0;
@autoreleasepool {
if (@available(iOS 14.0, tvOS 14.0, *)) {
NSError *error;

if (self->engine == nil) {
return SDL_SetError("Haptics engine was stopped");
}

if (intensity == 0.0f) {
if (self->player && self->active) {
[self->player stopAtTime:0 error:&error];
}
self->active = false;
return 0;
}

if (self->player == nil) {
CHHapticEventParameter *param = [[CHHapticEventParameter alloc] initWithParameterID:CHHapticEventParameterIDHapticIntensity value:1.0f];
CHHapticEvent *event = [[CHHapticEvent alloc] initWithEventType:CHHapticEventTypeHapticContinuous parameters:[NSArray arrayWithObjects:param, nil] relativeTime:0 duration:GCHapticDurationInfinite];
CHHapticPattern *pattern = [[CHHapticPattern alloc] initWithEvents:[NSArray arrayWithObject:event] parameters:[[NSArray alloc] init] error:&error];
if (error != nil) {
return SDL_SetError("Couldn't create haptic pattern: %s", [error.localizedDescription UTF8String]);
}

self->player = [self->engine createPlayerWithPattern:pattern error:&error];
if (error != nil) {
return SDL_SetError("Couldn't create haptic player: %s", [error.localizedDescription UTF8String]);
}
self->active = false;
}

CHHapticDynamicParameter *param = [[CHHapticDynamicParameter alloc] initWithParameterID:CHHapticDynamicParameterIDHapticIntensityControl value:intensity relativeTime:0];
[self->player sendParameters:[NSArray arrayWithObject:param] atTime:0 error:&error];
if (error != nil) {
return SDL_SetError("Couldn't update haptic player: %s", [error.localizedDescription UTF8String]);
}

if (!self->active) {
[self->player startAtTime:0 error:&error];
self->active = true;
}
}

return 0;
}
}

-(id) initWithController:(GCController*)controller locality:(GCHapticsLocality)locality API_AVAILABLE(ios(14.0), tvos(14.0))
{
NSError *error;

self->engine = [controller.haptics createEngineWithLocality:locality];
if (self->engine == nil) {
return nil;
}

[self->engine startAndReturnError:&error];
if (error != nil) {
return nil;
}

__weak typeof(self) weakSelf = self;
self->engine.stoppedHandler = ^(CHHapticEngineStoppedReason stoppedReason) {
SDL_RumbleMotor *_this = weakSelf;
if (_this == nil) {
return;
}

_this->player = nil;
_this->engine = nil;
};
self->engine.resetHandler = ^{
SDL_RumbleMotor *_this = weakSelf;
if (_this == nil) {
return;
}

_this->player = nil;
[_this->engine startAndReturnError:nil];
};

return self;
@autoreleasepool {
NSError *error;

self->engine = [controller.haptics createEngineWithLocality:locality];
if (self->engine == nil) {
SDL_SetError("Couldn't create haptics engine");
return nil;
}

[self->engine startAndReturnError:&error];
if (error != nil) {
SDL_SetError("Couldn't start haptics engine");
return nil;
}

__weak typeof(self) weakSelf = self;
self->engine.stoppedHandler = ^(CHHapticEngineStoppedReason stoppedReason) {
SDL_RumbleMotor *_this = weakSelf;
if (_this == nil) {
return;
}

_this->player = nil;
_this->engine = nil;
};
self->engine.resetHandler = ^{
SDL_RumbleMotor *_this = weakSelf;
if (_this == nil) {
return;
}

_this->player = nil;
[_this->engine startAndReturnError:nil];
};

return self;
}
}

@end
Expand Down Expand Up @@ -943,6 +958,12 @@ -(int) rumbleWithLowFrequency:(Uint16)low_frequency_rumble andHighFrequency:(Uin
return ((result < 0) ? -1 : 0);
}

-(void)cleanup
{
[self->low_frequency_motor cleanup];
[self->high_frequency_motor cleanup];
}

@end

static SDL_RumbleContext *IOS_JoystickInitRumble(GCController *controller)
Expand Down Expand Up @@ -1015,10 +1036,15 @@ -(int) rumbleWithLowFrequency:(Uint16)low_frequency_rumble andHighFrequency:(Uin
device->joystick = NULL;

@autoreleasepool {
#ifdef ENABLE_MFI_RUMBLE
if (device->rumble) {
SDL_RumbleContext *rumble = (__bridge SDL_RumbleContext *)device->rumble;

[rumble cleanup];
CFRelease(device->rumble);
device->rumble = NULL;
}
#endif /* ENABLE_MFI_RUMBLE */

if (device->accelerometer) {
#if !TARGET_OS_TV
Expand Down

0 comments on commit d9aea0c

Please sign in to comment.