test/testhaptic.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 25 Aug 2008 09:55:03 +0000
changeset 2713 0906692aa6a4
child 2748 5668c3dfe7bc
permissions -rw-r--r--
Final merge of Google Summer of Code 2008 work...

Force Feedback for SDL
by Edgar Simo, mentored by Ryan C. Gordon
slouken@2713
     1
/*
slouken@2713
     2
Copyright (c) 2008, Edgar Simo Serra
slouken@2713
     3
All rights reserved.
slouken@2713
     4
slouken@2713
     5
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
slouken@2713
     6
slouken@2713
     7
    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
slouken@2713
     8
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
slouken@2713
     9
    * Neither the name of the Simple Directmedia Layer (SDL) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
slouken@2713
    10
slouken@2713
    11
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
slouken@2713
    12
*/
slouken@2713
    13
slouken@2713
    14
/*
slouken@2713
    15
 * includes
slouken@2713
    16
 */
slouken@2713
    17
#include "SDL.h"
slouken@2713
    18
#include "SDL_haptic.h"
slouken@2713
    19
slouken@2713
    20
#include <stdio.h>              /* printf */
slouken@2713
    21
#include <string.h>             /* strstr */
slouken@2713
    22
slouken@2713
    23
slouken@2713
    24
slouken@2713
    25
static SDL_Haptic *haptic;
slouken@2713
    26
slouken@2713
    27
slouken@2713
    28
/*
slouken@2713
    29
 * prototypes
slouken@2713
    30
 */
slouken@2713
    31
static void abort_execution(void);
slouken@2713
    32
static void HapticPrintSupported(SDL_Haptic * haptic);
slouken@2713
    33
slouken@2713
    34
slouken@2713
    35
/**
slouken@2713
    36
 * @brief The entry point of this force feedback demo.
slouken@2713
    37
 * @param[in] argc Number of arguments.
slouken@2713
    38
 * @param[in] argv Array of argc arguments.
slouken@2713
    39
 */
slouken@2713
    40
int
slouken@2713
    41
main(int argc, char **argv)
slouken@2713
    42
{
slouken@2713
    43
    int i;
slouken@2713
    44
    char *name;
slouken@2713
    45
    SDL_HapticEffect efx[5];
slouken@2713
    46
    int id[5];
slouken@2713
    47
    int nefx;
slouken@2713
    48
    unsigned int supported;
slouken@2713
    49
slouken@2713
    50
    name = NULL;
slouken@2713
    51
    if (argc > 1) {
slouken@2713
    52
        name = argv[1];
slouken@2713
    53
        if ((strcmp(name, "--help") == 0) || (strcmp(name, "-h") == 0)) {
slouken@2713
    54
            printf("USAGE: %s [device name]\n"
slouken@2713
    55
                   "If device name is specified, it will try to find a device whose name\n"
slouken@2713
    56
                   "contains device name for testing.\n", argv[0]);
slouken@2713
    57
            return 0;
slouken@2713
    58
        }
slouken@2713
    59
    }
slouken@2713
    60
slouken@2713
    61
    /* Initialize the force feedbackness */
slouken@2713
    62
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK |
slouken@2713
    63
             SDL_INIT_HAPTIC);
slouken@2713
    64
    printf("%d Haptic devices detected.\n", SDL_NumHaptics());
slouken@2713
    65
    if (SDL_NumHaptics() > 0) {
slouken@2713
    66
        /* We'll just use the first force feedback device found */
slouken@2713
    67
        if (name == NULL) {
slouken@2713
    68
            i = 0;
slouken@2713
    69
        }
slouken@2713
    70
        /* Try to find matching device */
slouken@2713
    71
        else {
slouken@2713
    72
            for (i = 0; i < SDL_NumHaptics(); i++) {
slouken@2713
    73
                if (strstr(SDL_HapticName(i), name) != NULL)
slouken@2713
    74
                    break;
slouken@2713
    75
            }
slouken@2713
    76
slouken@2713
    77
            if (i >= SDL_NumHaptics()) {
slouken@2713
    78
                printf("Unable to find device matching '%s', aborting.\n",
slouken@2713
    79
                       name);
slouken@2713
    80
                return 1;
slouken@2713
    81
            }
slouken@2713
    82
        }
slouken@2713
    83
slouken@2713
    84
        haptic = SDL_HapticOpen(i);
slouken@2713
    85
        if (haptic == NULL) {
slouken@2713
    86
            perror("Unable to create the haptic device");
slouken@2713
    87
            return 1;
slouken@2713
    88
        }
slouken@2713
    89
        printf("Device: %s\n", SDL_HapticName(i));
slouken@2713
    90
        HapticPrintSupported(haptic);
slouken@2713
    91
    } else {
slouken@2713
    92
        printf("No Haptic devices found!\n");
slouken@2713
    93
        return 1;
slouken@2713
    94
    }
slouken@2713
    95
slouken@2713
    96
    /* We only want force feedback errors. */
slouken@2713
    97
    SDL_ClearError();
slouken@2713
    98
slouken@2713
    99
    /* Create effects. */
slouken@2713
   100
    memset(&efx, 0, sizeof(efx));
slouken@2713
   101
    nefx = 0;
slouken@2713
   102
    supported = SDL_HapticQuery(haptic);
slouken@2713
   103
slouken@2713
   104
    printf("\nUploading effects\n");
slouken@2713
   105
    /* First we'll try a SINE effect. */
slouken@2713
   106
    if (supported & SDL_HAPTIC_SINE) {
slouken@2713
   107
        printf("   effect %d: Sine Wave\n", nefx);
slouken@2713
   108
        efx[nefx].type = SDL_HAPTIC_SINE;
slouken@2713
   109
        efx[nefx].periodic.period = 1000;
slouken@2713
   110
        efx[nefx].periodic.magnitude = 0x4000;
slouken@2713
   111
        efx[nefx].periodic.length = 5000;
slouken@2713
   112
        efx[nefx].periodic.attack_length = 1000;
slouken@2713
   113
        efx[nefx].periodic.fade_length = 1000;
slouken@2713
   114
        id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
slouken@2713
   115
        if (id[nefx] < 0) {
slouken@2713
   116
            printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
slouken@2713
   117
            abort_execution();
slouken@2713
   118
        }
slouken@2713
   119
        nefx++;
slouken@2713
   120
    }
slouken@2713
   121
    /* Now we'll try a SAWTOOTHUP */
slouken@2713
   122
    if (supported & SDL_HAPTIC_SAWTOOTHUP) {
slouken@2713
   123
        printf("   effect %d: Sawtooth Up\n", nefx);
slouken@2713
   124
        efx[nefx].type = SDL_HAPTIC_SQUARE;
slouken@2713
   125
        efx[nefx].periodic.period = 500;
slouken@2713
   126
        efx[nefx].periodic.magnitude = 0x5000;
slouken@2713
   127
        efx[nefx].periodic.length = 5000;
slouken@2713
   128
        efx[nefx].periodic.attack_length = 1000;
slouken@2713
   129
        efx[nefx].periodic.fade_length = 1000;
slouken@2713
   130
        id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
slouken@2713
   131
        if (id[nefx] < 0) {
slouken@2713
   132
            printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
slouken@2713
   133
            abort_execution();
slouken@2713
   134
        }
slouken@2713
   135
        nefx++;
slouken@2713
   136
    }
slouken@2713
   137
    /* Now the classical constant effect. */
slouken@2713
   138
    if (supported & SDL_HAPTIC_CONSTANT) {
slouken@2713
   139
        printf("   effect %d: Constant Force\n", nefx);
slouken@2713
   140
        efx[nefx].type = SDL_HAPTIC_CONSTANT;
slouken@2713
   141
        efx[nefx].constant.direction.type = SDL_HAPTIC_POLAR;
slouken@2713
   142
        efx[nefx].constant.direction.dir[0] = 20000;    /* Force comes from the south-west. */
slouken@2713
   143
        efx[nefx].constant.length = 5000;
slouken@2713
   144
        efx[nefx].constant.level = 0x6000;
slouken@2713
   145
        efx[nefx].constant.attack_length = 1000;
slouken@2713
   146
        efx[nefx].constant.fade_length = 1000;
slouken@2713
   147
        id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
slouken@2713
   148
        if (id[nefx] < 0) {
slouken@2713
   149
            printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
slouken@2713
   150
            abort_execution();
slouken@2713
   151
        }
slouken@2713
   152
        nefx++;
slouken@2713
   153
    }
slouken@2713
   154
    /* The cute spring effect. */
slouken@2713
   155
    if (supported & SDL_HAPTIC_SPRING) {
slouken@2713
   156
        printf("   effect %d: Condition Spring\n", nefx);
slouken@2713
   157
        efx[nefx].type = SDL_HAPTIC_SPRING;
slouken@2713
   158
        efx[nefx].condition.length = 5000;
slouken@2713
   159
        for (i = 0; i < SDL_HapticNumAxes(haptic); i++) {
slouken@2713
   160
            efx[nefx].condition.right_sat[i] = 0x7FFF;
slouken@2713
   161
            efx[nefx].condition.left_sat[i] = 0x7FFF;
slouken@2713
   162
            efx[nefx].condition.right_coeff[i] = 0x2000;
slouken@2713
   163
            efx[nefx].condition.left_coeff[i] = 0x2000;
slouken@2713
   164
            efx[nefx].condition.center[i] = 0x1000;     /* Displace the center for it to move. */
slouken@2713
   165
        }
slouken@2713
   166
        id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
slouken@2713
   167
        if (id[nefx] < 0) {
slouken@2713
   168
            printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
slouken@2713
   169
            abort_execution();
slouken@2713
   170
        }
slouken@2713
   171
        nefx++;
slouken@2713
   172
    }
slouken@2713
   173
    /* The pretty awesome inertia effect. */
slouken@2713
   174
    if (supported & SDL_HAPTIC_INERTIA) {
slouken@2713
   175
        printf("   effect %d: Condition Inertia\n", nefx);
slouken@2713
   176
        efx[nefx].type = SDL_HAPTIC_SPRING;
slouken@2713
   177
        efx[nefx].condition.length = 5000;
slouken@2713
   178
        for (i = 0; i < SDL_HapticNumAxes(haptic); i++) {
slouken@2713
   179
            efx[nefx].condition.right_sat[i] = 0x7FFF;
slouken@2713
   180
            efx[nefx].condition.left_sat[i] = 0x7FFF;
slouken@2713
   181
            efx[nefx].condition.right_coeff[i] = 0x2000;
slouken@2713
   182
            efx[nefx].condition.left_coeff[i] = 0x2000;
slouken@2713
   183
        }
slouken@2713
   184
        id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
slouken@2713
   185
        if (id[nefx] < 0) {
slouken@2713
   186
            printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
slouken@2713
   187
            abort_execution();
slouken@2713
   188
        }
slouken@2713
   189
        nefx++;
slouken@2713
   190
    }
slouken@2713
   191
slouken@2713
   192
    printf
slouken@2713
   193
        ("\nNow playing effects for 5 seconds each with 1 second delay between\n");
slouken@2713
   194
    for (i = 0; i < nefx; i++) {
slouken@2713
   195
        printf("   Playing effect %d\n", i);
slouken@2713
   196
        SDL_HapticRunEffect(haptic, id[i], 1);
slouken@2713
   197
        SDL_Delay(6000);        /* Effects only have length 5000 */
slouken@2713
   198
    }
slouken@2713
   199
slouken@2713
   200
    /* Quit */
slouken@2713
   201
    if (haptic != NULL)
slouken@2713
   202
        SDL_HapticClose(haptic);
slouken@2713
   203
    SDL_Quit();
slouken@2713
   204
slouken@2713
   205
    return 0;
slouken@2713
   206
}
slouken@2713
   207
slouken@2713
   208
slouken@2713
   209
/*
slouken@2713
   210
 * Cleans up a bit.
slouken@2713
   211
 */
slouken@2713
   212
static void
slouken@2713
   213
abort_execution(void)
slouken@2713
   214
{
slouken@2713
   215
    printf("\nAborting program execution.\n");
slouken@2713
   216
slouken@2713
   217
    SDL_HapticClose(haptic);
slouken@2713
   218
    SDL_Quit();
slouken@2713
   219
slouken@2713
   220
    exit(1);
slouken@2713
   221
}
slouken@2713
   222
slouken@2713
   223
slouken@2713
   224
/*
slouken@2713
   225
 * Displays information about the haptic device.
slouken@2713
   226
 */
slouken@2713
   227
static void
slouken@2713
   228
HapticPrintSupported(SDL_Haptic * haptic)
slouken@2713
   229
{
slouken@2713
   230
    unsigned int supported;
slouken@2713
   231
slouken@2713
   232
    supported = SDL_HapticQuery(haptic);
slouken@2713
   233
    printf("   Supported effects [%d effects, %d playing]:\n",
slouken@2713
   234
           SDL_HapticNumEffects(haptic), SDL_HapticNumEffectsPlaying(haptic));
slouken@2713
   235
    if (supported & SDL_HAPTIC_CONSTANT)
slouken@2713
   236
        printf("      constant\n");
slouken@2713
   237
    if (supported & SDL_HAPTIC_SINE)
slouken@2713
   238
        printf("      sine\n");
slouken@2713
   239
    if (supported & SDL_HAPTIC_SQUARE)
slouken@2713
   240
        printf("      square\n");
slouken@2713
   241
    if (supported & SDL_HAPTIC_TRIANGLE)
slouken@2713
   242
        printf("      triangle\n");
slouken@2713
   243
    if (supported & SDL_HAPTIC_SAWTOOTHUP)
slouken@2713
   244
        printf("      sawtoothup\n");
slouken@2713
   245
    if (supported & SDL_HAPTIC_SAWTOOTHDOWN)
slouken@2713
   246
        printf("      sawtoothdown\n");
slouken@2713
   247
    if (supported & SDL_HAPTIC_RAMP)
slouken@2713
   248
        printf("      ramp\n");
slouken@2713
   249
    if (supported & SDL_HAPTIC_FRICTION)
slouken@2713
   250
        printf("      friction\n");
slouken@2713
   251
    if (supported & SDL_HAPTIC_SPRING)
slouken@2713
   252
        printf("      spring\n");
slouken@2713
   253
    if (supported & SDL_HAPTIC_DAMPER)
slouken@2713
   254
        printf("      damper\n");
slouken@2713
   255
    if (supported & SDL_HAPTIC_INERTIA)
slouken@2713
   256
        printf("      intertia\n");
slouken@2713
   257
    if (supported & SDL_HAPTIC_CUSTOM)
slouken@2713
   258
        printf("      custom\n");
slouken@2713
   259
    printf("   Supported capabilities:\n");
slouken@2713
   260
    if (supported & SDL_HAPTIC_GAIN)
slouken@2713
   261
        printf("      gain\n");
slouken@2713
   262
    if (supported & SDL_HAPTIC_AUTOCENTER)
slouken@2713
   263
        printf("      autocenter\n");
slouken@2713
   264
    if (supported & SDL_HAPTIC_STATUS)
slouken@2713
   265
        printf("      status\n");
slouken@2713
   266
}