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