src/haptic/SDL_haptic.c
author Edgar Simo <bobbens@gmail.com>
Tue, 15 Jul 2008 15:53:48 +0000
branchgsoc2008_force_feedback
changeset 2519 af9df9662807
parent 2517 37c13c12c878
child 2523 366d84fdf8d1
permissions -rw-r--r--
More explicit with iterations and length.
Added spherical coordinates (not available on linux).
     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 "../joystick/SDL_joystick_c.h" /* For SDL_PrivateJoystickValid */
    26 
    27 
    28 Uint8 SDL_numhaptics = 0;
    29 SDL_Haptic **SDL_haptics = NULL;
    30 
    31 
    32 /*
    33  * Initializes the Haptic devices.
    34  */
    35 int
    36 SDL_HapticInit(void)
    37 {  
    38    int arraylen;
    39    int status;
    40 
    41    SDL_numhaptics = 0;
    42    status = SDL_SYS_HapticInit();
    43    if (status >= 0) {
    44       arraylen = (status + 1) * sizeof(*SDL_haptics);
    45       SDL_haptics = (SDL_Haptic **) SDL_malloc(arraylen);
    46       if (SDL_haptics == NULL) { /* Out of memory. */
    47          SDL_numhaptics = 0;
    48       }
    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 valid;
    67    
    68    if (*haptic == NULL) {
    69       SDL_SetError("Haptic: Device hasn't been opened yet");
    70       valid = 0;
    71    } else {
    72       valid = 1;
    73    }
    74    return valid;
    75 }
    76 
    77 
    78 /*
    79  * Returns the number of available devices.
    80  */
    81 int
    82 SDL_NumHaptics(void)
    83 {
    84    return SDL_numhaptics;
    85 }
    86 
    87 
    88 /*
    89  * Gets the name of a Haptic device by index.
    90  */
    91 const char *
    92 SDL_HapticName(int device_index)
    93 {
    94    if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
    95       SDL_SetError("Haptic: There are %d haptic devices available", SDL_numhaptics);
    96       return NULL;
    97    }
    98    return SDL_SYS_HapticName(device_index);
    99 }
   100 
   101 
   102 /*
   103  * Opens a Haptic device.
   104  */
   105 SDL_Haptic *
   106 SDL_HapticOpen(int device_index)
   107 {
   108    int i;
   109    SDL_Haptic *haptic;
   110 
   111    if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
   112       SDL_SetError("Haptic: There are %d haptic devices available", SDL_numhaptics);
   113       return NULL;
   114    }
   115 
   116    /* If the haptic is already open, return it */
   117    for (i=0; SDL_haptics[i]; i++) {             
   118       if (device_index == SDL_haptics[i]->index) {
   119          haptic = SDL_haptics[i];
   120          ++haptic->ref_count;
   121          return haptic;
   122       }
   123    }
   124 
   125    /* Create the haptic device */
   126    haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
   127    if (haptic == NULL) {
   128       SDL_OutOfMemory();
   129       return NULL;
   130    }
   131 
   132    /* Initialize the haptic device */
   133    SDL_memset(haptic, 0, (sizeof *haptic));
   134    haptic->index = device_index;
   135    if (SDL_SYS_HapticOpen(haptic) < 0) {
   136       SDL_free(haptic);
   137       return NULL;
   138    }
   139 
   140    /* Disable autocenter and set gain to max. */
   141    if (haptic->supported & SDL_HAPTIC_GAIN)
   142       SDL_HapticSetGain(haptic,100);
   143    if (haptic->supported & SDL_HAPTIC_AUTOCENTER)
   144       SDL_HapticSetAutocenter(haptic,0);
   145 
   146    /* Add haptic to list */
   147    ++haptic->ref_count;
   148    for (i=0; SDL_haptics[i]; i++)
   149       /* Skip to next haptic */ ;
   150    SDL_haptics[i] = haptic;
   151 
   152    return haptic;
   153 }
   154 
   155 
   156 /*
   157  * Returns 1 if the device has been opened.
   158  */
   159 int
   160 SDL_HapticOpened(int device_index)
   161 {
   162    int i, opened;
   163 
   164    opened = 0;
   165    for (i=0; SDL_haptics[i]; i++) {
   166       if (SDL_haptics[i]->index == (Uint8) device_index) {
   167          opened = 1;
   168          break;
   169       }
   170    }
   171    return opened;
   172 }
   173 
   174 
   175 /*
   176  * Returns the index to a haptic device.
   177  */
   178 int
   179 SDL_HapticIndex(SDL_Haptic * haptic)
   180 {
   181    if (!ValidHaptic(&haptic)) {
   182       return -1;
   183    }
   184 
   185    return haptic->index;
   186 }
   187 
   188 
   189 /*
   190  * Returns SDL_TRUE if mouse is haptic, SDL_FALSE if it isn't.
   191  */
   192 int
   193 SDL_MouseIsHaptic(void)
   194 {
   195    if (SDL_SYS_HapticMouse() < 0)
   196       return SDL_FALSE;
   197    return SDL_TRUE;
   198 }
   199 
   200 
   201 /*
   202  * Returns the haptic device if mouse is haptic or NULL elsewise.
   203  */
   204 SDL_Haptic *
   205 SDL_HapticOpenFromMouse(void)
   206 {
   207    int device_index;
   208 
   209    device_index = SDL_SYS_HapticMouse();
   210 
   211    if (device_index < 0) {
   212       SDL_SetError("Haptic: Mouse isn't a haptic device.");
   213       return NULL;
   214    }
   215 
   216    return SDL_HapticOpen(device_index);
   217 }
   218 
   219 
   220 /*
   221  * Returns SDL_TRUE if joystick has haptic features.
   222  */
   223 int
   224 SDL_JoystickIsHaptic(SDL_Joystick * joystick)
   225 {
   226    int ret;
   227 
   228    /* Must be a valid joystick */
   229    if (!SDL_PrivateJoystickValid(&joystick)) {
   230       return -1;
   231    }
   232 
   233    ret = SDL_SYS_JoystickIsHaptic(joystick);
   234 
   235    if (ret > 0) return SDL_TRUE;
   236    else if (ret == 0) return SDL_FALSE;
   237    else return -1;
   238 }
   239 
   240 
   241 /*
   242  * Opens a haptic device from a joystick.
   243  */
   244 SDL_Haptic *
   245 SDL_HapticOpenFromJoystick(SDL_Joystick * joystick)
   246 {
   247    int i;
   248    SDL_Haptic *haptic;
   249 
   250    /* Must be a valid joystick */
   251    if (!SDL_PrivateJoystickValid(&joystick)) {
   252       return NULL;
   253    }
   254 
   255    /* Joystick must be haptic */
   256    if (SDL_SYS_JoystickIsHaptic(joystick) <= 0) {
   257       return NULL;
   258    }
   259 
   260    /* Check to see if joystick's haptic is already open */
   261    for (i=0; SDL_haptics[i]; i++) {
   262       if (SDL_SYS_JoystickSameHaptic(SDL_haptics[i],joystick)) {
   263          haptic = SDL_haptics[i];
   264          ++haptic->ref_count;
   265          return haptic;
   266       }
   267    }
   268 
   269    /* Create the haptic device */
   270    haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
   271    if (haptic == NULL) {
   272       SDL_OutOfMemory();
   273       return NULL;
   274    }
   275 
   276    /* Initialize the haptic device */
   277    SDL_memset(haptic, 0, (sizeof *haptic));
   278    if (SDL_SYS_HapticOpenFromJoystick(haptic,joystick) < 0) {
   279       SDL_free(haptic);
   280       return NULL;
   281    }
   282 
   283    /* Add haptic to list */
   284    ++haptic->ref_count;
   285    for (i=0; SDL_haptics[i]; i++)
   286       /* Skip to next haptic */ ;
   287    SDL_haptics[i] = haptic;
   288 
   289    return haptic;
   290 }
   291 
   292 
   293 /*
   294  * Closes a SDL_Haptic device.
   295  */
   296 void
   297 SDL_HapticClose(SDL_Haptic * haptic)
   298 {
   299    int i;
   300 
   301    /* Must be valid */
   302    if (!ValidHaptic(&haptic)) {
   303       return;
   304    }
   305 
   306    /* Check if it's still in use */
   307    if (--haptic->ref_count < 0) {
   308       return;
   309    }
   310 
   311    /* Close it, properly removing effects if needed */
   312    for (i=0; i<haptic->neffects; i++) {
   313       if (haptic->effects[i].hweffect != NULL) {
   314          SDL_HapticDestroyEffect(haptic,i);
   315       }
   316    }
   317    SDL_SYS_HapticClose(haptic);
   318 
   319    /* Remove from the list */
   320    for (i = 0; SDL_haptics[i]; ++i) {
   321       if (haptic == SDL_haptics[i]) {
   322          SDL_memcpy(&SDL_haptics[i], &SDL_haptics[i + 1],
   323                (SDL_numhaptics - i) * sizeof(haptic));
   324          break;
   325       }
   326    }
   327 
   328    /* Free */
   329    SDL_free(haptic);
   330 }
   331 
   332 /*
   333  * Cleans up after the subsystem.
   334  */
   335 void
   336 SDL_HapticQuit(void)
   337 {
   338    SDL_SYS_HapticQuit();
   339    if (SDL_haptics != NULL) {
   340       SDL_free(SDL_haptics);
   341       SDL_haptics = NULL;
   342    }
   343    SDL_numhaptics = 0;
   344 }
   345 
   346 /*
   347  * Returns the number of effects a haptic device has.
   348  */
   349 int
   350 SDL_HapticNumEffects(SDL_Haptic * haptic)
   351 {
   352    if (!ValidHaptic(&haptic)) {
   353       return -1;
   354    }
   355 
   356    return haptic->neffects;
   357 }
   358 
   359 
   360 /*
   361  * Returns the number of effects a haptic device can play.
   362  */
   363 int
   364 SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic)
   365 {
   366    if (!ValidHaptic(&haptic)) {
   367       return -1;
   368    }
   369 
   370    return haptic->nplaying;
   371 }
   372 
   373 
   374 /*
   375  * Returns supported effects by the device.
   376  */
   377 unsigned int
   378 SDL_HapticQuery(SDL_Haptic * haptic)
   379 {
   380    if (!ValidHaptic(&haptic)) {
   381       return -1;
   382    }
   383 
   384    return haptic->supported;
   385 }
   386 
   387 /*
   388  * Checks to see if the device can support the effect.
   389  */
   390 int
   391 SDL_HapticEffectSupported(SDL_Haptic * haptic, SDL_HapticEffect * effect)
   392 {
   393    if (!ValidHaptic(&haptic)) {
   394       return -1;
   395    }
   396 
   397    if ((haptic->supported & effect->type) != 0)
   398       return SDL_TRUE;
   399    return SDL_FALSE;
   400 }
   401 
   402 /*
   403  * Creates a new haptic effect.
   404  */
   405 int
   406 SDL_HapticNewEffect(SDL_Haptic * haptic, SDL_HapticEffect * effect)
   407 {
   408    int i;
   409 
   410    /* Check for device validity. */
   411    if (!ValidHaptic(&haptic)) {
   412       return -1;
   413    }
   414 
   415    /* Check to see if effect is supported */
   416    if (SDL_HapticEffectSupported(haptic,effect)==SDL_FALSE) {
   417       SDL_SetError("Haptic: Effect not supported by haptic device.");
   418       return -1;
   419    }
   420 
   421    /* See if there's a free slot */
   422    for (i=0; i<haptic->neffects; i++) {
   423       if (haptic->effects[i].hweffect == NULL) {
   424 
   425          /* Now let the backend create the real effect */
   426          if (SDL_SYS_HapticNewEffect(haptic,&haptic->effects[i],effect) != 0) {
   427             return -1; /* Backend failed to create effect */
   428          }
   429          return i;
   430       }
   431    }
   432 
   433    SDL_SetError("Haptic: Device has no free space left.");
   434    return -1;
   435 }
   436 
   437 /*
   438  * Checks to see if an effect is valid.
   439  */
   440 static int
   441 ValidEffect(SDL_Haptic * haptic, int effect)
   442 {
   443    if ((effect < 0) || (effect >= haptic->neffects)) {
   444       SDL_SetError("Haptic: Invalid effect identifier.");
   445       return 0;
   446    }
   447    return 1;
   448 }
   449 
   450 /*
   451  * Updates an effect.
   452  */
   453 int
   454 SDL_HapticUpdateEffect(SDL_Haptic * haptic, int effect, SDL_HapticEffect * data)
   455 {
   456    if (!ValidHaptic(&haptic) || !ValidEffect(haptic,effect)) {
   457       return -1;
   458    }
   459 
   460    /* Updates the effect */
   461    if (SDL_SYS_HapticUpdateEffect(haptic,&haptic->effects[effect],data) < 0) {
   462       return -1;
   463    }
   464 
   465    return 0;
   466 }
   467 
   468 
   469 /*
   470  * Runs the haptic effect on the device.
   471  */
   472 int
   473 SDL_HapticRunEffect(SDL_Haptic * haptic, int effect, Uint32 iterations)
   474 {
   475    if (!ValidHaptic(&haptic) || !ValidEffect(haptic,effect)) {
   476       return -1;
   477    }
   478 
   479    /* Run the effect */
   480    if (SDL_SYS_HapticRunEffect(haptic,&haptic->effects[effect], iterations) < 0) {
   481       return -1;
   482    }
   483 
   484    return 0;
   485 }
   486 
   487 /*
   488  * Stops the haptic effect on the device.
   489  */
   490 int
   491 SDL_HapticStopEffect(SDL_Haptic * haptic, int effect)
   492 {
   493    if (!ValidHaptic(&haptic) || !ValidEffect(haptic,effect)) {
   494       return -1;
   495    }
   496 
   497    /* Stop the effect */
   498    if (SDL_SYS_HapticStopEffect(haptic,&haptic->effects[effect]) < 0) {
   499       return -1;
   500    }
   501 
   502    return 0;
   503 }
   504 
   505 /*
   506  * Gets rid of a haptic effect.
   507  */
   508 void
   509 SDL_HapticDestroyEffect(SDL_Haptic * haptic, int effect)
   510 {
   511    if (!ValidHaptic(&haptic) || !ValidEffect(haptic,effect)) {
   512       return;
   513    }
   514 
   515    /* Not allocated */
   516    if (haptic->effects[effect].hweffect == NULL) {
   517       return;
   518    }
   519 
   520    SDL_SYS_HapticDestroyEffect(haptic, &haptic->effects[effect]);
   521 }
   522 
   523 /*
   524  * Gets the status of a haptic effect.
   525  */
   526 int
   527 SDL_HapticGetEffectStatus(SDL_Haptic *haptic, int effect)
   528 {
   529    if (!ValidHaptic(&haptic) || !ValidEffect(haptic,effect)) {
   530       return -1;
   531    }
   532 
   533    if ((haptic->supported & SDL_HAPTIC_STATUS) == 0) {
   534       SDL_SetError("Haptic: Device does not support status queries.");
   535       return -1;
   536    }
   537 
   538    return SDL_SYS_HapticGetEffectStatus(haptic, &haptic->effects[effect]);
   539 }
   540 
   541 /*
   542  * Sets the global gain of the device.
   543  */
   544 int
   545 SDL_HapticSetGain(SDL_Haptic * haptic, int gain )
   546 {
   547    const char *env;
   548    int real_gain, max_gain;
   549 
   550    if (!ValidHaptic(&haptic)) {
   551       return -1;
   552    }
   553 
   554    if ((haptic->supported & SDL_HAPTIC_GAIN) == 0) {
   555       SDL_SetError("Haptic: Device does not support setting gain.");
   556       return -1;
   557    }
   558 
   559    if ((gain < 0) || (gain > 100)) {
   560       SDL_SetError("Haptic: Gain must be between 0 and 100.");
   561       return -1;
   562    }
   563 
   564    /* We use the envvar to get the maximum gain. */
   565    env = SDL_getenv("SDL_HAPTIC_GAIN_MAX");
   566    if (env != NULL) {
   567       max_gain = SDL_atoi(env);
   568 
   569       /* Check for sanity. */
   570       if (max_gain < 0) max_gain = 0;
   571       else if (max_gain > 100) max_gain = 100;
   572 
   573       /* We'll scale it linearly with SDL_HAPTIC_GAIN_MAX */
   574       real_gain = (gain * max_gain) / 100;
   575    }
   576    else {
   577       real_gain = gain;
   578    }
   579 
   580    if (SDL_SYS_HapticSetGain(haptic,real_gain) < 0) {
   581       return -1;
   582    }
   583 
   584    return 0;
   585 }
   586 
   587 /*
   588  * Makes the device autocenter, 0 disables.
   589  */
   590 int
   591 SDL_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter )
   592 {
   593    if (!ValidHaptic(&haptic)) {
   594       return -1;
   595    }
   596 
   597    if ((haptic->supported & SDL_HAPTIC_AUTOCENTER) == 0) {
   598       SDL_SetError("Haptic: Device does not support setting autocenter.");
   599       return -1;
   600    }
   601 
   602    if ((autocenter < 0) || (autocenter > 100)) {
   603       SDL_SetError("Haptic: Autocenter must be between 0 and 100.");
   604       return -1;
   605    }                                           
   606 
   607    if (SDL_SYS_HapticSetAutocenter(haptic,autocenter) < 0) {
   608       return -1;
   609    }
   610 
   611    return 0;
   612 }
   613 
   614