src/haptic/SDL_haptic.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 20 Feb 2011 13:56:57 -0800
changeset 5362 074fc8730031
parent 5360 220d3af9121f
child 5535 96594ac5fd1a
permissions -rw-r--r--
Fixed compiler warning
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 2008 Edgar Simo
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #include "SDL_syshaptic.h"
    25 #include "SDL_haptic_c.h"
    26 #include "../joystick/SDL_joystick_c.h" /* For SDL_PrivateJoystickValid */
    27 
    28 
    29 Uint8 SDL_numhaptics = 0;
    30 SDL_Haptic **SDL_haptics = NULL;
    31 
    32 
    33 /*
    34  * Initializes the Haptic devices.
    35  */
    36 int
    37 SDL_HapticInit(void)
    38 {
    39     int arraylen;
    40     int status;
    41 
    42     SDL_numhaptics = 0;
    43     status = SDL_SYS_HapticInit();
    44     if (status >= 0) {
    45         arraylen = (status + 1) * sizeof(*SDL_haptics);
    46         SDL_haptics = (SDL_Haptic **) SDL_malloc(arraylen);
    47         if (SDL_haptics == NULL) {      /* Out of memory. */
    48             SDL_numhaptics = 0;
    49         } else {
    50             SDL_memset(SDL_haptics, 0, arraylen);
    51             SDL_numhaptics = status;
    52         }
    53         status = 0;
    54     }
    55 
    56     return status;
    57 }
    58 
    59 
    60 /*
    61  * Checks to see if the haptic device is valid
    62  */
    63 static int
    64 ValidHaptic(SDL_Haptic * haptic)
    65 {
    66     int i;
    67     int valid;
    68 
    69     valid = 0;
    70     if (haptic != NULL) {
    71         for (i = 0; i < SDL_numhaptics; i++) {
    72             if (SDL_haptics[i] == haptic) {
    73                 valid = 1;
    74                 break;
    75             }
    76         }
    77     }
    78 
    79     /* Create the error here. */
    80     if (valid == 0) {
    81         SDL_SetError("Haptic: Invalid haptic device identifier");
    82     }
    83 
    84     return valid;
    85 }
    86 
    87 
    88 /*
    89  * Returns the number of available devices.
    90  */
    91 int
    92 SDL_NumHaptics(void)
    93 {
    94     return SDL_numhaptics;
    95 }
    96 
    97 
    98 /*
    99  * Gets the name of a Haptic device by index.
   100  */
   101 const char *
   102 SDL_HapticName(int device_index)
   103 {
   104     if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
   105         SDL_SetError("Haptic: There are %d haptic devices available",
   106                      SDL_numhaptics);
   107         return NULL;
   108     }
   109     return SDL_SYS_HapticName(device_index);
   110 }
   111 
   112 
   113 /*
   114  * Opens a Haptic device.
   115  */
   116 SDL_Haptic *
   117 SDL_HapticOpen(int device_index)
   118 {
   119     int i;
   120     SDL_Haptic *haptic;
   121 
   122     if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
   123         SDL_SetError("Haptic: There are %d haptic devices available",
   124                      SDL_numhaptics);
   125         return NULL;
   126     }
   127 
   128     /* If the haptic is already open, return it */
   129     for (i = 0; SDL_haptics[i]; i++) {
   130         if (device_index == SDL_haptics[i]->index) {
   131             haptic = SDL_haptics[i];
   132             ++haptic->ref_count;
   133             return haptic;
   134         }
   135     }
   136 
   137     /* Create the haptic device */
   138     haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
   139     if (haptic == NULL) {
   140         SDL_OutOfMemory();
   141         return NULL;
   142     }
   143 
   144     /* Initialize the haptic device */
   145     SDL_memset(haptic, 0, (sizeof *haptic));
   146     haptic->rumble_id = -1;
   147     haptic->index = device_index;
   148     if (SDL_SYS_HapticOpen(haptic) < 0) {
   149         SDL_free(haptic);
   150         return NULL;
   151     }
   152 
   153     /* Disable autocenter and set gain to max. */
   154     if (haptic->supported & SDL_HAPTIC_GAIN)
   155         SDL_HapticSetGain(haptic, 100);
   156     if (haptic->supported & SDL_HAPTIC_AUTOCENTER)
   157         SDL_HapticSetAutocenter(haptic, 0);
   158 
   159     /* Add haptic to list */
   160     ++haptic->ref_count;
   161     for (i = 0; SDL_haptics[i]; i++)
   162         /* Skip to next haptic */ ;
   163     SDL_haptics[i] = haptic;
   164 
   165     return haptic;
   166 }
   167 
   168 
   169 /*
   170  * Returns 1 if the device has been opened.
   171  */
   172 int
   173 SDL_HapticOpened(int device_index)
   174 {
   175     int i, opened;
   176 
   177     opened = 0;
   178     for (i = 0; SDL_haptics[i]; i++) {
   179         if (SDL_haptics[i]->index == (Uint8) device_index) {
   180             opened = 1;
   181             break;
   182         }
   183     }
   184     return opened;
   185 }
   186 
   187 
   188 /*
   189  * Returns the index to a haptic device.
   190  */
   191 int
   192 SDL_HapticIndex(SDL_Haptic * haptic)
   193 {
   194     if (!ValidHaptic(haptic)) {
   195         return -1;
   196     }
   197 
   198     return haptic->index;
   199 }
   200 
   201 
   202 /*
   203  * Returns SDL_TRUE if mouse is haptic, SDL_FALSE if it isn't.
   204  */
   205 int
   206 SDL_MouseIsHaptic(void)
   207 {
   208     if (SDL_SYS_HapticMouse() < 0)
   209         return SDL_FALSE;
   210     return SDL_TRUE;
   211 }
   212 
   213 
   214 /*
   215  * Returns the haptic device if mouse is haptic or NULL elsewise.
   216  */
   217 SDL_Haptic *
   218 SDL_HapticOpenFromMouse(void)
   219 {
   220     int device_index;
   221 
   222     device_index = SDL_SYS_HapticMouse();
   223 
   224     if (device_index < 0) {
   225         SDL_SetError("Haptic: Mouse isn't a haptic device.");
   226         return NULL;
   227     }
   228 
   229     return SDL_HapticOpen(device_index);
   230 }
   231 
   232 
   233 /*
   234  * Returns SDL_TRUE if joystick has haptic features.
   235  */
   236 int
   237 SDL_JoystickIsHaptic(SDL_Joystick * joystick)
   238 {
   239     int ret;
   240 
   241     /* Must be a valid joystick */
   242     if (!SDL_PrivateJoystickValid(&joystick)) {
   243         return -1;
   244     }
   245 
   246     ret = SDL_SYS_JoystickIsHaptic(joystick);
   247 
   248     if (ret > 0)
   249         return SDL_TRUE;
   250     else if (ret == 0)
   251         return SDL_FALSE;
   252     else
   253         return -1;
   254 }
   255 
   256 
   257 /*
   258  * Opens a haptic device from a joystick.
   259  */
   260 SDL_Haptic *
   261 SDL_HapticOpenFromJoystick(SDL_Joystick * joystick)
   262 {
   263     int i;
   264     SDL_Haptic *haptic;
   265 
   266     /* Must be a valid joystick */
   267     if (!SDL_PrivateJoystickValid(&joystick)) {
   268         SDL_SetError("Haptic: Joystick isn't valid.");
   269         return NULL;
   270     }
   271 
   272     /* Joystick must be haptic */
   273     if (SDL_SYS_JoystickIsHaptic(joystick) <= 0) {
   274         SDL_SetError("Haptic: Joystick isn't a haptic device.");
   275         return NULL;
   276     }
   277 
   278     /* Check to see if joystick's haptic is already open */
   279     for (i = 0; SDL_haptics[i]; i++) {
   280         if (SDL_SYS_JoystickSameHaptic(SDL_haptics[i], joystick)) {
   281             haptic = SDL_haptics[i];
   282             ++haptic->ref_count;
   283             return haptic;
   284         }
   285     }
   286 
   287     /* Create the haptic device */
   288     haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
   289     if (haptic == NULL) {
   290         SDL_OutOfMemory();
   291         return NULL;
   292     }
   293 
   294     /* Initialize the haptic device */
   295     SDL_memset(haptic, 0, sizeof(SDL_Haptic));
   296     haptic->rumble_id = -1;
   297     if (SDL_SYS_HapticOpenFromJoystick(haptic, joystick) < 0) {
   298         SDL_free(haptic);
   299         return NULL;
   300     }
   301 
   302     /* Add haptic to list */
   303     ++haptic->ref_count;
   304     for (i = 0; SDL_haptics[i]; i++)
   305         /* Skip to next haptic */ ;
   306     SDL_haptics[i] = haptic;
   307 
   308     return haptic;
   309 }
   310 
   311 
   312 /*
   313  * Closes a SDL_Haptic device.
   314  */
   315 void
   316 SDL_HapticClose(SDL_Haptic * haptic)
   317 {
   318     int i;
   319 
   320     /* Must be valid */
   321     if (!ValidHaptic(haptic)) {
   322         return;
   323     }
   324 
   325     /* Check if it's still in use */
   326     if (--haptic->ref_count < 0) {
   327         return;
   328     }
   329 
   330     /* Close it, properly removing effects if needed */
   331     for (i = 0; i < haptic->neffects; i++) {
   332         if (haptic->effects[i].hweffect != NULL) {
   333             SDL_HapticDestroyEffect(haptic, i);
   334         }
   335     }
   336     SDL_SYS_HapticClose(haptic);
   337 
   338     /* Remove from the list */
   339     for (i = 0; SDL_haptics[i]; ++i) {
   340         if (haptic == SDL_haptics[i]) {
   341             SDL_haptics[i] = NULL;
   342             SDL_memcpy(&SDL_haptics[i], &SDL_haptics[i + 1],
   343                        (SDL_numhaptics - i) * sizeof(haptic));
   344             break;
   345         }
   346     }
   347 
   348     /* Free */
   349     SDL_free(haptic);
   350 }
   351 
   352 /*
   353  * Cleans up after the subsystem.
   354  */
   355 void
   356 SDL_HapticQuit(void)
   357 {
   358     SDL_SYS_HapticQuit();
   359     if (SDL_haptics != NULL) {
   360         SDL_free(SDL_haptics);
   361         SDL_haptics = NULL;
   362     }
   363     SDL_numhaptics = 0;
   364 }
   365 
   366 /*
   367  * Returns the number of effects a haptic device has.
   368  */
   369 int
   370 SDL_HapticNumEffects(SDL_Haptic * haptic)
   371 {
   372     if (!ValidHaptic(haptic)) {
   373         return -1;
   374     }
   375 
   376     return haptic->neffects;
   377 }
   378 
   379 
   380 /*
   381  * Returns the number of effects a haptic device can play.
   382  */
   383 int
   384 SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic)
   385 {
   386     if (!ValidHaptic(haptic)) {
   387         return -1;
   388     }
   389 
   390     return haptic->nplaying;
   391 }
   392 
   393 
   394 /*
   395  * Returns supported effects by the device.
   396  */
   397 unsigned int
   398 SDL_HapticQuery(SDL_Haptic * haptic)
   399 {
   400     if (!ValidHaptic(haptic)) {
   401         return -1;
   402     }
   403 
   404     return haptic->supported;
   405 }
   406 
   407 
   408 /*
   409  * Returns the number of axis on the device.
   410  */
   411 int
   412 SDL_HapticNumAxes(SDL_Haptic * haptic)
   413 {
   414     if (!ValidHaptic(haptic)) {
   415         return -1;
   416     }
   417 
   418     return haptic->naxes;
   419 }
   420 
   421 /*
   422  * Checks to see if the device can support the effect.
   423  */
   424 int
   425 SDL_HapticEffectSupported(SDL_Haptic * haptic, SDL_HapticEffect * effect)
   426 {
   427     if (!ValidHaptic(haptic)) {
   428         return -1;
   429     }
   430 
   431     if ((haptic->supported & effect->type) != 0)
   432         return SDL_TRUE;
   433     return SDL_FALSE;
   434 }
   435 
   436 /*
   437  * Creates a new haptic effect.
   438  */
   439 int
   440 SDL_HapticNewEffect(SDL_Haptic * haptic, SDL_HapticEffect * effect)
   441 {
   442     int i;
   443 
   444     /* Check for device validity. */
   445     if (!ValidHaptic(haptic)) {
   446         return -1;
   447     }
   448 
   449     /* Check to see if effect is supported */
   450     if (SDL_HapticEffectSupported(haptic, effect) == SDL_FALSE) {
   451         SDL_SetError("Haptic: Effect not supported by haptic device.");
   452         return -1;
   453     }
   454 
   455     /* See if there's a free slot */
   456     for (i = 0; i < haptic->neffects; i++) {
   457         if (haptic->effects[i].hweffect == NULL) {
   458 
   459             /* Now let the backend create the real effect */
   460             if (SDL_SYS_HapticNewEffect(haptic, &haptic->effects[i], effect)
   461                 != 0) {
   462                 return -1;      /* Backend failed to create effect */
   463             }
   464 
   465             SDL_memcpy(&haptic->effects[i].effect, effect,
   466                        sizeof(SDL_HapticEffect));
   467             return i;
   468         }
   469     }
   470 
   471     SDL_SetError("Haptic: Device has no free space left.");
   472     return -1;
   473 }
   474 
   475 /*
   476  * Checks to see if an effect is valid.
   477  */
   478 static int
   479 ValidEffect(SDL_Haptic * haptic, int effect)
   480 {
   481     if ((effect < 0) || (effect >= haptic->neffects)) {
   482         SDL_SetError("Haptic: Invalid effect identifier.");
   483         return 0;
   484     }
   485     return 1;
   486 }
   487 
   488 /*
   489  * Updates an effect.
   490  */
   491 int
   492 SDL_HapticUpdateEffect(SDL_Haptic * haptic, int effect,
   493                        SDL_HapticEffect * data)
   494 {
   495     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   496         return -1;
   497     }
   498 
   499     /* Can't change type dynamically. */
   500     if (data->type != haptic->effects[effect].effect.type) {
   501         SDL_SetError("Haptic: Updating effect type is illegal.");
   502         return -1;
   503     }
   504 
   505     /* Updates the effect */
   506     if (SDL_SYS_HapticUpdateEffect(haptic, &haptic->effects[effect], data) <
   507         0) {
   508         return -1;
   509     }
   510 
   511     SDL_memcpy(&haptic->effects[effect].effect, data,
   512                sizeof(SDL_HapticEffect));
   513     return 0;
   514 }
   515 
   516 
   517 /*
   518  * Runs the haptic effect on the device.
   519  */
   520 int
   521 SDL_HapticRunEffect(SDL_Haptic * haptic, int effect, Uint32 iterations)
   522 {
   523     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   524         return -1;
   525     }
   526 
   527     /* Run the effect */
   528     if (SDL_SYS_HapticRunEffect(haptic, &haptic->effects[effect], iterations)
   529         < 0) {
   530         return -1;
   531     }
   532 
   533     return 0;
   534 }
   535 
   536 /*
   537  * Stops the haptic effect on the device.
   538  */
   539 int
   540 SDL_HapticStopEffect(SDL_Haptic * haptic, int effect)
   541 {
   542     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   543         return -1;
   544     }
   545 
   546     /* Stop the effect */
   547     if (SDL_SYS_HapticStopEffect(haptic, &haptic->effects[effect]) < 0) {
   548         return -1;
   549     }
   550 
   551     return 0;
   552 }
   553 
   554 /*
   555  * Gets rid of a haptic effect.
   556  */
   557 void
   558 SDL_HapticDestroyEffect(SDL_Haptic * haptic, int effect)
   559 {
   560     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   561         return;
   562     }
   563 
   564     /* Not allocated */
   565     if (haptic->effects[effect].hweffect == NULL) {
   566         return;
   567     }
   568 
   569     SDL_SYS_HapticDestroyEffect(haptic, &haptic->effects[effect]);
   570 }
   571 
   572 /*
   573  * Gets the status of a haptic effect.
   574  */
   575 int
   576 SDL_HapticGetEffectStatus(SDL_Haptic * haptic, int effect)
   577 {
   578     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   579         return -1;
   580     }
   581 
   582     if ((haptic->supported & SDL_HAPTIC_STATUS) == 0) {
   583         SDL_SetError("Haptic: Device does not support status queries.");
   584         return -1;
   585     }
   586 
   587     return SDL_SYS_HapticGetEffectStatus(haptic, &haptic->effects[effect]);
   588 }
   589 
   590 /*
   591  * Sets the global gain of the device.
   592  */
   593 int
   594 SDL_HapticSetGain(SDL_Haptic * haptic, int gain)
   595 {
   596     const char *env;
   597     int real_gain, max_gain;
   598 
   599     if (!ValidHaptic(haptic)) {
   600         return -1;
   601     }
   602 
   603     if ((haptic->supported & SDL_HAPTIC_GAIN) == 0) {
   604         SDL_SetError("Haptic: Device does not support setting gain.");
   605         return -1;
   606     }
   607 
   608     if ((gain < 0) || (gain > 100)) {
   609         SDL_SetError("Haptic: Gain must be between 0 and 100.");
   610         return -1;
   611     }
   612 
   613     /* We use the envvar to get the maximum gain. */
   614     env = SDL_getenv("SDL_HAPTIC_GAIN_MAX");
   615     if (env != NULL) {
   616         max_gain = SDL_atoi(env);
   617 
   618         /* Check for sanity. */
   619         if (max_gain < 0)
   620             max_gain = 0;
   621         else if (max_gain > 100)
   622             max_gain = 100;
   623 
   624         /* We'll scale it linearly with SDL_HAPTIC_GAIN_MAX */
   625         real_gain = (gain * max_gain) / 100;
   626     } else {
   627         real_gain = gain;
   628     }
   629 
   630     if (SDL_SYS_HapticSetGain(haptic, real_gain) < 0) {
   631         return -1;
   632     }
   633 
   634     return 0;
   635 }
   636 
   637 /*
   638  * Makes the device autocenter, 0 disables.
   639  */
   640 int
   641 SDL_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
   642 {
   643     if (!ValidHaptic(haptic)) {
   644         return -1;
   645     }
   646 
   647     if ((haptic->supported & SDL_HAPTIC_AUTOCENTER) == 0) {
   648         SDL_SetError("Haptic: Device does not support setting autocenter.");
   649         return -1;
   650     }
   651 
   652     if ((autocenter < 0) || (autocenter > 100)) {
   653         SDL_SetError("Haptic: Autocenter must be between 0 and 100.");
   654         return -1;
   655     }
   656 
   657     if (SDL_SYS_HapticSetAutocenter(haptic, autocenter) < 0) {
   658         return -1;
   659     }
   660 
   661     return 0;
   662 }
   663 
   664 /*
   665  * Pauses the haptic device.
   666  */
   667 int
   668 SDL_HapticPause(SDL_Haptic * haptic)
   669 {
   670     if (!ValidHaptic(haptic)) {
   671         return -1;
   672     }
   673 
   674     if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) {
   675         SDL_SetError("Haptic: Device does not support setting pausing.");
   676         return -1;
   677     }
   678 
   679     return SDL_SYS_HapticPause(haptic);
   680 }
   681 
   682 /*
   683  * Unpauses the haptic device.
   684  */
   685 int
   686 SDL_HapticUnpause(SDL_Haptic * haptic)
   687 {
   688     if (!ValidHaptic(haptic)) {
   689         return -1;
   690     }
   691 
   692     if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) {
   693         return 0;               /* Not going to be paused, so we pretend it's unpaused. */
   694     }
   695 
   696     return SDL_SYS_HapticUnpause(haptic);
   697 }
   698 
   699 /*
   700  * Stops all the currently playing effects.
   701  */
   702 int
   703 SDL_HapticStopAll(SDL_Haptic * haptic)
   704 {
   705     if (!ValidHaptic(haptic)) {
   706         return -1;
   707     }
   708 
   709     return SDL_SYS_HapticStopAll(haptic);
   710 }
   711 
   712 static void
   713 SDL_HapticRumbleCreate(SDL_HapticEffect * efx)
   714 {
   715    SDL_memset(efx, 0, sizeof(SDL_HapticEffect));
   716    efx->type = SDL_HAPTIC_SINE;
   717    efx->periodic.period = 1000;
   718    efx->periodic.magnitude = 0x4000;
   719    efx->periodic.length = 5000;
   720    efx->periodic.attack_length = 0;
   721    efx->periodic.fade_length = 0;
   722 }
   723 
   724 /*
   725  * Checks to see if rumble is supported.
   726  */
   727 int
   728 SDL_HapticRumbleSupported(SDL_Haptic * haptic)
   729 {
   730     SDL_HapticEffect efx;
   731 
   732     if (!ValidHaptic(haptic)) {
   733         return -1;
   734     }
   735 
   736     SDL_HapticRumbleCreate(&efx);
   737     return SDL_HapticEffectSupported(haptic, &efx);
   738 }
   739 
   740 /*
   741  * Initializes the haptic device for simple rumble playback.
   742  */
   743 int
   744 SDL_HapticRumbleInit(SDL_Haptic * haptic)
   745 {
   746     if (!ValidHaptic(haptic)) {
   747         return -1;
   748     }
   749 
   750     /* Already allocated. */
   751     if (haptic->rumble_id >= 0) {
   752         return 0;
   753     }
   754 
   755     /* Copy over. */
   756     SDL_HapticRumbleCreate(&haptic->rumble_effect);
   757     haptic->rumble_id = SDL_HapticNewEffect(haptic, &haptic->rumble_effect);
   758     if (haptic->rumble_id >= 0) {
   759         return 0;
   760     }
   761     return -1;
   762 }
   763 
   764 /*
   765  * Runs simple rumble on a haptic device
   766  */
   767 int
   768 SDL_HapticRumblePlay(SDL_Haptic * haptic, float strength, Uint32 length)
   769 {
   770     int ret;
   771     SDL_HapticPeriodic *efx;
   772 
   773     if (!ValidHaptic(haptic)) {
   774         return -1;
   775     }
   776 
   777     if (haptic->rumble_id < 0) {
   778         SDL_SetError("Haptic: Rumble effect not initialized on haptic device");
   779         return -1;
   780     }
   781 
   782     /* Clamp strength. */
   783     if (strength > 1.0f) {
   784         strength = 1.0f;
   785     }
   786     else if (strength < 0.0f) {
   787         strength = 0.0f;
   788     }
   789 
   790     /* New effect. */
   791     efx = &haptic->rumble_effect.periodic;
   792     efx->magnitude = (Sint16)(32767.0f*strength);
   793     efx->length = length;
   794     ret = SDL_HapticUpdateEffect(haptic, haptic->rumble_id, &haptic->rumble_effect);
   795 
   796     return SDL_HapticRunEffect(haptic, haptic->rumble_id, 1);
   797 }
   798 
   799 /*
   800  * Stops the simple rumble on a haptic device.
   801  */
   802 int
   803 SDL_HapticRumbleStop(SDL_Haptic * haptic)
   804 {
   805     if (!ValidHaptic(haptic)) {
   806         return -1;
   807     }
   808 
   809     if (haptic->rumble_id < 0) {
   810         SDL_SetError("Haptic: Rumble effect not initialized on haptic device");
   811         return -1;
   812     }
   813 
   814     return SDL_HapticStopEffect(haptic, haptic->rumble_id);
   815 }
   816 
   817