From 8c66898765fb91aef13984de5c245c614723bab2 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Thu, 15 Oct 2020 18:40:13 -0500 Subject: [PATCH] Dynamically update haptic effects instead of creating new players all the time --- Limelight/Input/HapticContext.m | 60 +++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/Limelight/Input/HapticContext.m b/Limelight/Input/HapticContext.m index 66d8217..5f6e186 100644 --- a/Limelight/Input/HapticContext.m +++ b/Limelight/Input/HapticContext.m @@ -15,6 +15,7 @@ GCControllerPlayerIndex _playerIndex; CHHapticEngine* _hapticEngine API_AVAILABLE(ios(13.0), tvos(14.0)); id _hapticPlayer API_AVAILABLE(ios(13.0), tvos(14.0)); + BOOL _playing; } -(void)cleanup API_AVAILABLE(ios(14.0), tvos(14.0)) { @@ -30,42 +31,55 @@ -(void)setMotorAmplitude:(unsigned short)amplitude API_AVAILABLE(ios(14.0), tvos(14.0)) { NSError* error; - - // Cancel the last haptic effect - if (_hapticPlayer != nil) { - [_hapticPlayer stopAtTime:0 error:&error]; - _hapticPlayer = nil; - } // Check if the haptic engine died if (_hapticEngine == nil) { return; } - // Don't bother queuing a 0 amplitude haptic event + // Stop the effect entirely if the amplitude is 0 if (amplitude == 0) { + if (_playing) { + [_hapticPlayer stopAtTime:0 error:&error]; + _playing = NO; + } + return; } - CHHapticEventParameter* intensityParameter = [[CHHapticEventParameter alloc] initWithParameterID:CHHapticEventParameterIDHapticIntensity value:amplitude / 65536.0f]; - CHHapticEvent* hapticEvent = [[CHHapticEvent alloc] initWithEventType:CHHapticEventTypeHapticContinuous parameters:[NSArray arrayWithObjects:intensityParameter, nil] relativeTime:0 duration:GCHapticDurationInfinite]; - CHHapticPattern* hapticPattern = [[CHHapticPattern alloc] initWithEvents:[NSArray arrayWithObject:hapticEvent] parameters:[[NSArray alloc] init] error:&error]; + if (_hapticPlayer == nil) { + // We must initialize the intensity to 1.0f because the dynamic parameters are multiplied by this value before being applied + CHHapticEventParameter* intensityParameter = [[CHHapticEventParameter alloc] initWithParameterID:CHHapticEventParameterIDHapticIntensity value:1.0f]; + CHHapticEvent* hapticEvent = [[CHHapticEvent alloc] initWithEventType:CHHapticEventTypeHapticContinuous parameters:[NSArray arrayWithObject:intensityParameter] relativeTime:0 duration:GCHapticDurationInfinite]; + CHHapticPattern* hapticPattern = [[CHHapticPattern alloc] initWithEvents:[NSArray arrayWithObject:hapticEvent] parameters:[[NSArray alloc] init] error:&error]; + if (error != nil) { + Log(LOG_W, @"Controller %d: Haptic pattern creation failed: %@", _playerIndex, error); + return; + } + + _hapticPlayer = [_hapticEngine createPlayerWithPattern:hapticPattern error:&error]; + if (error != nil) { + Log(LOG_W, @"Controller %d: Haptic player creation failed: %@", _playerIndex, error); + return; + } + } + + CHHapticDynamicParameter* intensityParameter = [[CHHapticDynamicParameter alloc] initWithParameterID:CHHapticDynamicParameterIDHapticIntensityControl value:amplitude / 65536.0f relativeTime:0]; + [_hapticPlayer sendParameters:[NSArray arrayWithObject:intensityParameter] atTime:CHHapticTimeImmediate error:&error]; if (error != nil) { - Log(LOG_W, @"Controller %d: Haptic pattern creation failed: %@", _playerIndex, error); + Log(LOG_W, @"Controller %d: Haptic player parameter update failed: %@", _playerIndex, error); return; } - _hapticPlayer = [_hapticEngine createPlayerWithPattern:hapticPattern error:&error]; - if (error != nil) { - Log(LOG_W, @"Controller %d: Haptic player creation failed: %@", _playerIndex, error); - return; - } - - [_hapticPlayer startAtTime:0 error:&error]; - if (error != nil) { - _hapticPlayer = nil; - Log(LOG_W, @"Controller %d: Haptic playback start failed: %@", _playerIndex, error); - return; + if (!_playing) { + [_hapticPlayer startAtTime:0 error:&error]; + if (error != nil) { + _hapticPlayer = nil; + Log(LOG_W, @"Controller %d: Haptic playback start failed: %@", _playerIndex, error); + return; + } + + _playing = YES; } } @@ -95,6 +109,7 @@ Log(LOG_W, @"Controller %d: Haptic engine stopped: %p", me->_playerIndex, stoppedReason); me->_hapticPlayer = nil; me->_hapticEngine = nil; + me->_playing = NO; }; _hapticEngine.resetHandler = ^{ HapticContext* me = weakSelf; @@ -104,6 +119,7 @@ Log(LOG_W, @"Controller %d: Haptic engine reset", me->_playerIndex); me->_hapticPlayer = nil; + me->_playing = NO; [me->_hapticEngine startAndReturnError:nil]; };