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