src/haptic/SDL_haptic.c
author Edgar Simo <bobbens@gmail.com>
Tue, 08 Jul 2008 19:23:03 +0000
branchgsoc2008_force_feedback
changeset 2505 abfcba0f3bd1
parent 2497 0893fbf73b3d
child 2506 ba8e99fe92c1
permissions -rw-r--r--
Added SDL_HapticIndex.
     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 static Uint8 SDL_numhaptics = 0;
    29 SDL_Haptic **SDL_haptics = NULL;
    30 static SDL_Haptic *default_haptic = 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) {
    48          SDL_numhaptics = 0;
    49       } else {
    50          SDL_memset(SDL_haptics, 0, arraylen);
    51          SDL_numhaptics = status;
    52       }
    53       status = 0;
    54    }
    55    default_haptic = NULL;
    56 
    57    return status;
    58 }
    59 
    60 
    61 /*
    62  * Checks to see if the haptic device is valid
    63  */
    64 static int
    65 ValidHaptic(SDL_Haptic ** haptic)
    66 {
    67    int valid;
    68    
    69    if (*haptic == NULL) {
    70       SDL_SetError("Haptic device hasn't been opened yet");
    71       valid = 0;
    72    } else {
    73       valid = 1;
    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_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("There are %d haptic devices available", SDL_numhaptics);
    97       return NULL;
    98    }
    99    return SDL_SYS_HapticName(device_index);
   100 }
   101 
   102 
   103 /*
   104  * Opens a Haptic device.
   105  */
   106 SDL_Haptic *
   107 SDL_HapticOpen(int device_index)
   108 {
   109    int i;
   110    SDL_Haptic *haptic;
   111 
   112    if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
   113       SDL_SetError("There are %d haptic devices available", SDL_numhaptics);
   114       return NULL;
   115    }
   116 
   117    /* If the haptic is already open, return it */
   118    for (i=0; SDL_haptics[i]; i++) {             
   119       if (device_index == SDL_haptics[i]->index) {
   120          haptic = SDL_haptics[i];
   121          ++haptic->ref_count;
   122          return haptic;
   123       }
   124    }
   125 
   126    /* Create the haptic device */
   127    haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
   128    if (haptic == NULL) {
   129       SDL_OutOfMemory();
   130       return NULL;
   131    }
   132 
   133    /* Initialize the haptic device */
   134    SDL_memset(haptic, 0, (sizeof *haptic));
   135    haptic->index = device_index;
   136    if (SDL_SYS_HapticOpen(haptic) < 0) {
   137       SDL_free(haptic);
   138       return NULL;
   139    }
   140 
   141    /* Add haptic to list */
   142    ++haptic->ref_count;
   143    for (i=0; SDL_haptics[i]; i++)
   144       /* Skip to next haptic */ ;
   145    SDL_haptics[i] = haptic;
   146 
   147    return haptic;
   148 }
   149 
   150 
   151 /*
   152  * Returns the index to a haptic device.
   153  */
   154 int
   155 SDL_HapticIndex(SDL_Haptic * haptic)
   156 {
   157    if (!ValidHaptic(&haptic)) {
   158       return -1;
   159    }
   160 
   161    return haptic->index;
   162 }
   163 
   164 
   165 /*
   166  * Returns SDL_TRUE if joystick has haptic features.
   167  */
   168 int
   169 SDL_JoystickIsHaptic(SDL_Joystick * joystick)
   170 {
   171    int ret;
   172 
   173    /* Must be a valid joystick */
   174    if (!SDL_PrivateJoystickValid(&joystick)) {
   175       return -1;
   176    }
   177 
   178    ret = SDL_SYS_JoystickIsHaptic(joystick);
   179 
   180    if (ret > 0) return SDL_TRUE;
   181    else if (ret == 0) return SDL_FALSE;
   182    else return -1;
   183 }
   184 
   185 
   186 /*
   187  * Opens a haptic device from a joystick.
   188  */
   189 SDL_Haptic *
   190 SDL_HapticOpenFromJoystick(SDL_Joystick * joystick)
   191 {
   192    int i;
   193    SDL_Haptic *haptic;
   194 
   195    /* Must be a valid joystick */
   196    if (!SDL_PrivateJoystickValid(&joystick)) {
   197       return NULL;
   198    }
   199 
   200    /* Joystick must be haptic */
   201    if (SDL_SYS_JoystickIsHaptic(joystick) <= 0) {
   202       return NULL;
   203    }
   204 
   205    /* Check to see if joystick's haptic is already open */
   206    for (i=0; SDL_haptics[i]; i++) {
   207       if (SDL_SYS_JoystickSameHaptic(SDL_haptics[i],joystick)) {
   208          haptic = SDL_haptics[i];
   209          ++haptic->ref_count;
   210          return haptic;
   211       }
   212    }
   213 
   214    /* Create the haptic device */
   215    haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
   216    if (haptic == NULL) {
   217       SDL_OutOfMemory();
   218       return NULL;
   219    }
   220 
   221    /* Initialize the haptic device */
   222    SDL_memset(haptic, 0, (sizeof *haptic));
   223    if (SDL_SYS_HapticOpenFromJoystick(haptic,joystick) < 0) {
   224       SDL_free(haptic);
   225       return NULL;
   226    }
   227 
   228    /* Add haptic to list */
   229    ++haptic->ref_count;
   230    for (i=0; SDL_haptics[i]; i++)
   231       /* Skip to next haptic */ ;
   232    SDL_haptics[i] = haptic;
   233 
   234    return haptic;
   235 }
   236 
   237 
   238 /*
   239  * Closes a SDL_Haptic device.
   240  */
   241 void
   242 SDL_HapticClose(SDL_Haptic * haptic)
   243 {
   244    int i;
   245 
   246    /* Must be valid */
   247    if (!ValidHaptic(&haptic)) {
   248       return;
   249    }
   250 
   251    /* Check if it's still in use */
   252    if (--haptic->ref_count < 0) {
   253       return;
   254    }
   255 
   256    /* Close it, properly removing effects if needed */
   257    for (i=0; i<haptic->neffects; i++) {
   258       if (haptic->effects[i].hweffect != NULL) {
   259          SDL_HapticDestroyEffect(haptic,i);
   260       }
   261    }
   262    SDL_SYS_HapticClose(haptic);
   263 
   264    /* Remove from the list */
   265    for (i = 0; SDL_haptics[i]; ++i) {
   266       if (haptic == SDL_haptics[i]) {
   267          SDL_memcpy(&SDL_haptics[i], &SDL_haptics[i + 1],
   268                (SDL_numhaptics - i) * sizeof(haptic));
   269          break;
   270       }
   271    }
   272 
   273    /* Free */
   274    SDL_free(haptic);
   275 }
   276 
   277 /*
   278  * Cleans up after the subsystem.
   279  */
   280 void
   281 SDL_HapticQuit(void)
   282 {
   283    SDL_numhaptics = 0;
   284 
   285    SDL_SYS_HapticQuit();
   286    if (SDL_haptics != NULL) {
   287       SDL_free(SDL_haptics);
   288       SDL_haptics = NULL;
   289    }
   290 }
   291 
   292 /*
   293  * Returns the number of effects a haptic device has.
   294  */
   295 int
   296 SDL_HapticNumEffects(SDL_Haptic * haptic)
   297 {
   298    if (!ValidHaptic(&haptic)) {
   299       return -1;
   300    }
   301 
   302    return haptic->neffects;
   303 }
   304 
   305 /*
   306  * Returns supported effects by the device.
   307  */
   308 unsigned int
   309 SDL_HapticQuery(SDL_Haptic * haptic)
   310 {
   311    if (!ValidHaptic(&haptic)) {
   312       return -1;
   313    }
   314 
   315    return haptic->supported;
   316 }
   317 
   318 /*
   319  * Checks to see if the device can support the effect.
   320  */
   321 int
   322 SDL_HapticEffectSupported(SDL_Haptic * haptic, SDL_HapticEffect * effect)
   323 {
   324    if (!ValidHaptic(&haptic)) {
   325       return -1;
   326    }
   327 
   328    if ((haptic->supported & effect->type) != 0)
   329       return SDL_TRUE;
   330    return SDL_FALSE;
   331 }
   332 
   333 /*
   334  * Creates a new haptic effect.
   335  */
   336 int
   337 SDL_HapticNewEffect(SDL_Haptic * haptic, SDL_HapticEffect * effect)
   338 {
   339    int i;
   340 
   341    /* Check for device validity. */
   342    if (!ValidHaptic(&haptic)) {
   343       return -1;
   344    }
   345 
   346    /* Check to see if effect is supported */
   347    if (SDL_HapticEffectSupported(haptic,effect)==SDL_FALSE) {
   348       SDL_SetError("Haptic effect not supported by haptic device.");
   349       return -1;
   350    }
   351 
   352    /* See if there's a free slot */
   353    for (i=0; i<haptic->neffects; i++) {
   354       if (haptic->effects[i].hweffect == NULL) {
   355 
   356          /* Now let the backend create the real effect */
   357          if (SDL_SYS_HapticNewEffect(haptic,&haptic->effects[i],effect) != 0) {
   358             return -1; /* Backend failed to create effect */
   359          }
   360          return i;
   361       }
   362    }
   363 
   364    SDL_SetError("Haptic device has no free space left.");
   365    return -1;
   366 }
   367 
   368 /*
   369  * Checks to see if an effect is valid.
   370  */
   371 static int
   372 ValidEffect(SDL_Haptic * haptic, int effect)
   373 {
   374    if ((effect < 0) || (effect >= haptic->neffects)) {
   375       SDL_SetError("Invalid haptic effect identifier.");
   376       return 0;
   377    }
   378    return 1;
   379 }
   380 
   381 /*
   382  * Updates an effect.
   383  */
   384 int
   385 SDL_HapticUpdateEffect(SDL_Haptic * haptic, int effect, SDL_HapticEffect * data)
   386 {
   387    if (!ValidHaptic(&haptic) || !ValidEffect(haptic,effect)) {
   388       return -1;
   389    }
   390 
   391    /* Updates the effect */
   392    if (SDL_SYS_HapticUpdateEffect(haptic,&haptic->effects[effect],data) < 0) {
   393       return -1;
   394    }
   395 
   396    return 0;
   397 }
   398 
   399 
   400 /*
   401  * Runs the haptic effect on the device.
   402  */
   403 int
   404 SDL_HapticRunEffect(SDL_Haptic * haptic, int effect)
   405 {
   406    if (!ValidHaptic(&haptic) || !ValidEffect(haptic,effect)) {
   407       return -1;
   408    }
   409 
   410    /* Run the effect */
   411    if (SDL_SYS_HapticRunEffect(haptic,&haptic->effects[effect]) < 0) {
   412       return -1;
   413    }
   414 
   415    return 0;
   416 }
   417 
   418 /*
   419  * Stops the haptic effect on the device.
   420  */
   421 int
   422 SDL_HapticStopEffect(SDL_Haptic * haptic, int effect)
   423 {
   424    if (!ValidHaptic(&haptic) || !ValidEffect(haptic,effect)) {
   425       return -1;
   426    }
   427 
   428    /* Stop the effect */
   429    if (SDL_SYS_HapticStopEffect(haptic,&haptic->effects[effect]) < 0) {
   430       return -1;
   431    }
   432 
   433    return 0;
   434 }
   435 
   436 /*
   437  * Gets rid of a haptic effect.
   438  */
   439 void
   440 SDL_HapticDestroyEffect(SDL_Haptic * haptic, int effect)
   441 {
   442    if (!ValidHaptic(&haptic) || !ValidEffect(haptic,effect)) {
   443       return;
   444    }
   445 
   446    /* Not allocated */
   447    if (haptic->effects[effect].hweffect == NULL) {
   448       return;
   449    }
   450 
   451    SDL_SYS_HapticDestroyEffect(haptic, &haptic->effects[effect]);
   452 }
   453 
   454 /*
   455  * Gets the status of a haptic effect.
   456  */
   457 int
   458 SDL_HapticGetEffectStatus(SDL_Haptic *haptic, int effect)
   459 {
   460    if (!ValidHaptic(&haptic) || !ValidEffect(haptic,effect)) {
   461       return -1;
   462    }
   463 
   464    if ((haptic->supported & SDL_HAPTIC_STATUS) == 0) {
   465       SDL_SetError("Haptic device does not support status queries.");
   466       return -1;
   467    }
   468 
   469    return SDL_SYS_HapticGetEffectStatus(haptic, &haptic->effects[effect]);
   470 }
   471 
   472 /*
   473  * Sets the global gain of the device.
   474  */
   475 int
   476 SDL_HapticSetGain(SDL_Haptic * haptic, int gain )
   477 {
   478    if (!ValidHaptic(&haptic)) {
   479       return -1;
   480    }
   481 
   482    if ((haptic->supported & SDL_HAPTIC_GAIN) == 0) {
   483       SDL_SetError("Haptic device does not support setting gain.");
   484       return -1;
   485    }
   486 
   487    if ((gain < 0) || (gain > 100)) {
   488       SDL_SetError("Haptic gain must be between 0 and 100.");
   489       return -1;
   490    }
   491 
   492    if (SDL_SYS_HapticSetGain(haptic,gain) < 0) {
   493       return -1;
   494    }
   495 
   496    return 0;
   497 }
   498 
   499 /*
   500  * Makes the device autocenter, 0 disables.
   501  */
   502 int
   503 SDL_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter )
   504 {
   505    if (!ValidHaptic(&haptic)) {
   506       return -1;
   507    }
   508 
   509    if ((haptic->supported & SDL_HAPTIC_AUTOCENTER) == 0) {
   510       SDL_SetError("Haptic device does not support setting autocenter.");
   511       return -1;
   512    }
   513 
   514    if ((autocenter < 0) || (autocenter > 100)) {
   515       SDL_SetError("Haptic autocenter must be between 0 and 100.");
   516       return -1;
   517    }                                           
   518 
   519    if (SDL_SYS_HapticSetAutocenter(haptic,autocenter) < 0) {
   520       return -1;
   521    }
   522 
   523    return 0;
   524 }
   525 
   526