test/testhaptic.c
author Ryan C. Gordon <icculus@icculus.org>
Sat, 10 Aug 2013 13:38:09 -0400
changeset 7621 5caa5fb3deb6
parent 7517 965d57022c01
child 7629 a0a3bd77cbc4
permissions -rw-r--r--
Replaced SDL_HAPTIC_SQUARE with SDL_HAPTIC_LEFTRIGHT.

We needed a bit, so we're hoping no one needs this effect, especially when
it's fairly close to SDL_HAPTIC_SINE, we hope.

SDL_HAPTIC_LEFTRIGHT maps to XInput's functionality, so this removes the SINE
code for the XInput driver to keep things clean.

This also makes the simplified Rumble API use SDL_HAPTIC_LEFTRIGHT if
SDL_HAPTIC_SINE isn't available, to keep XInput working.

When we break the ABI, and can extend the supported capabilities field from
a Uint16, we'll add SDL_HAPTIC_SQUARE back in.

This patch is based on work by Ethan Lee.
slouken@5535
     1
/*
slouken@7517
     2
  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
slouken@5535
     3
slouken@5535
     4
  This software is provided 'as-is', without any express or implied
slouken@5535
     5
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     6
  arising from the use of this software.
slouken@5535
     7
slouken@5535
     8
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
     9
  including commercial applications, and to alter it and redistribute it
slouken@5535
    10
  freely.
slouken@5535
    11
*/
slouken@2713
    12
/*
slouken@2713
    13
Copyright (c) 2008, Edgar Simo Serra
slouken@2713
    14
All rights reserved.
slouken@2713
    15
slouken@2713
    16
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
slouken@2713
    17
slouken@2713
    18
    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
slouken@2713
    19
    * 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
    20
    * 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
    21
slouken@2713
    22
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
    23
*/
slouken@2713
    24
slouken@2713
    25
/*
slouken@2713
    26
 * includes
slouken@2713
    27
 */
slouken@3338
    28
#include <stdlib.h>
slouken@2713
    29
#include <stdio.h>              /* printf */
slouken@2713
    30
#include <string.h>             /* strstr */
bobbens@2748
    31
#include <ctype.h>              /* isdigit */
slouken@2713
    32
aschiffler@6771
    33
#include "SDL.h"
aschiffler@6771
    34
aschiffler@6771
    35
#ifndef SDL_HAPTIC_DISABLED
aschiffler@6771
    36
aschiffler@6771
    37
#include "SDL_haptic.h"
slouken@2713
    38
slouken@2713
    39
static SDL_Haptic *haptic;
slouken@2713
    40
slouken@2713
    41
slouken@2713
    42
/*
slouken@2713
    43
 * prototypes
slouken@2713
    44
 */
slouken@2713
    45
static void abort_execution(void);
slouken@2713
    46
static void HapticPrintSupported(SDL_Haptic * haptic);
slouken@2713
    47
slouken@2713
    48
slouken@2713
    49
/**
slouken@2713
    50
 * @brief The entry point of this force feedback demo.
slouken@2713
    51
 * @param[in] argc Number of arguments.
slouken@2713
    52
 * @param[in] argv Array of argc arguments.
slouken@2713
    53
 */
slouken@2713
    54
int
slouken@2713
    55
main(int argc, char **argv)
slouken@2713
    56
{
slouken@2713
    57
    int i;
slouken@2713
    58
    char *name;
bobbens@2748
    59
    int index;
slouken@2713
    60
    SDL_HapticEffect efx[5];
slouken@2713
    61
    int id[5];
slouken@2713
    62
    int nefx;
slouken@2713
    63
    unsigned int supported;
slouken@2713
    64
slouken@2713
    65
    name = NULL;
bobbens@2748
    66
    index = -1;
slouken@2713
    67
    if (argc > 1) {
slouken@2713
    68
        name = argv[1];
slouken@2713
    69
        if ((strcmp(name, "--help") == 0) || (strcmp(name, "-h") == 0)) {
bobbens@2748
    70
            printf("USAGE: %s [device]\n"
bobbens@2748
    71
                   "If device is a two-digit number it'll use it as an index, otherwise\n"
bobbens@2748
    72
                   "it'll use it as if it were part of the device's name.\n",
bobbens@2748
    73
                   argv[0]);
slouken@2713
    74
            return 0;
slouken@2713
    75
        }
bobbens@2748
    76
bobbens@2748
    77
        i = strlen(name);
bobbens@2748
    78
        if ((i < 3) && isdigit(name[0]) && ((i == 1) || isdigit(name[1]))) {
bobbens@2748
    79
            index = atoi(name);
bobbens@2748
    80
            name = NULL;
bobbens@2748
    81
        }
slouken@2713
    82
    }
slouken@2713
    83
slouken@2713
    84
    /* Initialize the force feedbackness */
slouken@2713
    85
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK |
slouken@2713
    86
             SDL_INIT_HAPTIC);
slouken@2713
    87
    printf("%d Haptic devices detected.\n", SDL_NumHaptics());
slouken@2713
    88
    if (SDL_NumHaptics() > 0) {
bobbens@2748
    89
        /* We'll just use index or the first force feedback device found */
slouken@2713
    90
        if (name == NULL) {
bobbens@2748
    91
            i = (index != -1) ? index : 0;
slouken@2713
    92
        }
slouken@2713
    93
        /* Try to find matching device */
slouken@2713
    94
        else {
slouken@2713
    95
            for (i = 0; i < SDL_NumHaptics(); i++) {
slouken@2713
    96
                if (strstr(SDL_HapticName(i), name) != NULL)
slouken@2713
    97
                    break;
slouken@2713
    98
            }
slouken@2713
    99
slouken@2713
   100
            if (i >= SDL_NumHaptics()) {
slouken@2713
   101
                printf("Unable to find device matching '%s', aborting.\n",
slouken@2713
   102
                       name);
slouken@2713
   103
                return 1;
slouken@2713
   104
            }
slouken@2713
   105
        }
slouken@2713
   106
slouken@2713
   107
        haptic = SDL_HapticOpen(i);
slouken@2713
   108
        if (haptic == NULL) {
bobbens@2748
   109
            printf("Unable to create the haptic device: %s\n",
bobbens@2748
   110
                   SDL_GetError());
slouken@2713
   111
            return 1;
slouken@2713
   112
        }
slouken@2713
   113
        printf("Device: %s\n", SDL_HapticName(i));
slouken@2713
   114
        HapticPrintSupported(haptic);
slouken@2713
   115
    } else {
slouken@2713
   116
        printf("No Haptic devices found!\n");
slouken@2713
   117
        return 1;
slouken@2713
   118
    }
slouken@2713
   119
slouken@2713
   120
    /* We only want force feedback errors. */
slouken@2713
   121
    SDL_ClearError();
slouken@2713
   122
slouken@2713
   123
    /* Create effects. */
slouken@2713
   124
    memset(&efx, 0, sizeof(efx));
slouken@2713
   125
    nefx = 0;
slouken@2713
   126
    supported = SDL_HapticQuery(haptic);
slouken@2713
   127
slouken@2713
   128
    printf("\nUploading effects\n");
slouken@2713
   129
    /* First we'll try a SINE effect. */
slouken@2713
   130
    if (supported & SDL_HAPTIC_SINE) {
slouken@2713
   131
        printf("   effect %d: Sine Wave\n", nefx);
slouken@2713
   132
        efx[nefx].type = SDL_HAPTIC_SINE;
slouken@2713
   133
        efx[nefx].periodic.period = 1000;
slouken@2713
   134
        efx[nefx].periodic.magnitude = 0x4000;
slouken@2713
   135
        efx[nefx].periodic.length = 5000;
slouken@2713
   136
        efx[nefx].periodic.attack_length = 1000;
slouken@2713
   137
        efx[nefx].periodic.fade_length = 1000;
slouken@2713
   138
        id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
slouken@2713
   139
        if (id[nefx] < 0) {
slouken@2713
   140
            printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
slouken@2713
   141
            abort_execution();
slouken@2713
   142
        }
slouken@2713
   143
        nefx++;
slouken@2713
   144
    }
slouken@2713
   145
    /* Now we'll try a SAWTOOTHUP */
slouken@2713
   146
    if (supported & SDL_HAPTIC_SAWTOOTHUP) {
slouken@2713
   147
        printf("   effect %d: Sawtooth Up\n", nefx);
philipp@7263
   148
        efx[nefx].type = SDL_HAPTIC_SAWTOOTHUP;
slouken@2713
   149
        efx[nefx].periodic.period = 500;
slouken@2713
   150
        efx[nefx].periodic.magnitude = 0x5000;
slouken@2713
   151
        efx[nefx].periodic.length = 5000;
slouken@2713
   152
        efx[nefx].periodic.attack_length = 1000;
slouken@2713
   153
        efx[nefx].periodic.fade_length = 1000;
slouken@2713
   154
        id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
slouken@2713
   155
        if (id[nefx] < 0) {
slouken@2713
   156
            printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
slouken@2713
   157
            abort_execution();
slouken@2713
   158
        }
slouken@2713
   159
        nefx++;
slouken@2713
   160
    }
slouken@2713
   161
    /* Now the classical constant effect. */
slouken@2713
   162
    if (supported & SDL_HAPTIC_CONSTANT) {
slouken@2713
   163
        printf("   effect %d: Constant Force\n", nefx);
slouken@2713
   164
        efx[nefx].type = SDL_HAPTIC_CONSTANT;
slouken@2713
   165
        efx[nefx].constant.direction.type = SDL_HAPTIC_POLAR;
slouken@2713
   166
        efx[nefx].constant.direction.dir[0] = 20000;    /* Force comes from the south-west. */
slouken@2713
   167
        efx[nefx].constant.length = 5000;
slouken@2713
   168
        efx[nefx].constant.level = 0x6000;
slouken@2713
   169
        efx[nefx].constant.attack_length = 1000;
slouken@2713
   170
        efx[nefx].constant.fade_length = 1000;
slouken@2713
   171
        id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
slouken@2713
   172
        if (id[nefx] < 0) {
slouken@2713
   173
            printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
slouken@2713
   174
            abort_execution();
slouken@2713
   175
        }
slouken@2713
   176
        nefx++;
slouken@2713
   177
    }
slouken@2713
   178
    /* The cute spring effect. */
slouken@2713
   179
    if (supported & SDL_HAPTIC_SPRING) {
slouken@2713
   180
        printf("   effect %d: Condition Spring\n", nefx);
slouken@2713
   181
        efx[nefx].type = SDL_HAPTIC_SPRING;
slouken@2713
   182
        efx[nefx].condition.length = 5000;
slouken@2713
   183
        for (i = 0; i < SDL_HapticNumAxes(haptic); i++) {
slouken@2713
   184
            efx[nefx].condition.right_sat[i] = 0x7FFF;
slouken@2713
   185
            efx[nefx].condition.left_sat[i] = 0x7FFF;
slouken@2713
   186
            efx[nefx].condition.right_coeff[i] = 0x2000;
slouken@2713
   187
            efx[nefx].condition.left_coeff[i] = 0x2000;
slouken@2713
   188
            efx[nefx].condition.center[i] = 0x1000;     /* Displace the center for it to move. */
slouken@2713
   189
        }
slouken@2713
   190
        id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
slouken@2713
   191
        if (id[nefx] < 0) {
slouken@2713
   192
            printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
slouken@2713
   193
            abort_execution();
slouken@2713
   194
        }
slouken@2713
   195
        nefx++;
slouken@2713
   196
    }
slouken@2713
   197
    /* The pretty awesome inertia effect. */
slouken@2713
   198
    if (supported & SDL_HAPTIC_INERTIA) {
slouken@2713
   199
        printf("   effect %d: Condition Inertia\n", nefx);
slouken@2713
   200
        efx[nefx].type = SDL_HAPTIC_SPRING;
slouken@2713
   201
        efx[nefx].condition.length = 5000;
slouken@2713
   202
        for (i = 0; i < SDL_HapticNumAxes(haptic); i++) {
slouken@2713
   203
            efx[nefx].condition.right_sat[i] = 0x7FFF;
slouken@2713
   204
            efx[nefx].condition.left_sat[i] = 0x7FFF;
slouken@2713
   205
            efx[nefx].condition.right_coeff[i] = 0x2000;
slouken@2713
   206
            efx[nefx].condition.left_coeff[i] = 0x2000;
slouken@2713
   207
        }
slouken@2713
   208
        id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
slouken@2713
   209
        if (id[nefx] < 0) {
slouken@2713
   210
            printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
slouken@2713
   211
            abort_execution();
slouken@2713
   212
        }
slouken@2713
   213
        nefx++;
slouken@2713
   214
    }
slouken@2713
   215
icculus@7621
   216
    /* First we'll try a SINE effect. */
icculus@7621
   217
    if (supported & SDL_HAPTIC_LEFTRIGHT) {
icculus@7621
   218
        printf("   effect %d: Left/Right\n", nefx);
icculus@7621
   219
        efx[nefx].type = SDL_HAPTIC_LEFTRIGHT;
icculus@7621
   220
        efx[nefx].leftright.length = 5000;
icculus@7621
   221
        efx[nefx].leftright.large_magnitude = 0x3000;
icculus@7621
   222
        efx[nefx].leftright.small_magnitude = 0xFFFF;
icculus@7621
   223
        id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
icculus@7621
   224
        if (id[nefx] < 0) {
icculus@7621
   225
            printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
icculus@7621
   226
            abort_execution();
icculus@7621
   227
        }
icculus@7621
   228
        nefx++;
icculus@7621
   229
    }
icculus@7621
   230
icculus@7621
   231
slouken@2713
   232
    printf
slouken@2713
   233
        ("\nNow playing effects for 5 seconds each with 1 second delay between\n");
slouken@2713
   234
    for (i = 0; i < nefx; i++) {
slouken@2713
   235
        printf("   Playing effect %d\n", i);
slouken@2713
   236
        SDL_HapticRunEffect(haptic, id[i], 1);
slouken@2713
   237
        SDL_Delay(6000);        /* Effects only have length 5000 */
slouken@2713
   238
    }
slouken@2713
   239
slouken@2713
   240
    /* Quit */
slouken@2713
   241
    if (haptic != NULL)
slouken@2713
   242
        SDL_HapticClose(haptic);
slouken@2713
   243
    SDL_Quit();
slouken@2713
   244
slouken@2713
   245
    return 0;
slouken@2713
   246
}
slouken@2713
   247
slouken@2713
   248
slouken@2713
   249
/*
slouken@2713
   250
 * Cleans up a bit.
slouken@2713
   251
 */
slouken@2713
   252
static void
slouken@2713
   253
abort_execution(void)
slouken@2713
   254
{
slouken@2713
   255
    printf("\nAborting program execution.\n");
slouken@2713
   256
slouken@2713
   257
    SDL_HapticClose(haptic);
slouken@2713
   258
    SDL_Quit();
slouken@2713
   259
slouken@2713
   260
    exit(1);
slouken@2713
   261
}
slouken@2713
   262
slouken@2713
   263
slouken@2713
   264
/*
slouken@2713
   265
 * Displays information about the haptic device.
slouken@2713
   266
 */
slouken@2713
   267
static void
slouken@2713
   268
HapticPrintSupported(SDL_Haptic * haptic)
slouken@2713
   269
{
slouken@2713
   270
    unsigned int supported;
slouken@2713
   271
slouken@2713
   272
    supported = SDL_HapticQuery(haptic);
slouken@2713
   273
    printf("   Supported effects [%d effects, %d playing]:\n",
slouken@2713
   274
           SDL_HapticNumEffects(haptic), SDL_HapticNumEffectsPlaying(haptic));
slouken@2713
   275
    if (supported & SDL_HAPTIC_CONSTANT)
slouken@2713
   276
        printf("      constant\n");
slouken@2713
   277
    if (supported & SDL_HAPTIC_SINE)
slouken@2713
   278
        printf("      sine\n");
icculus@7621
   279
    /* !!! FIXME: put this back when we have more bits in 2.1 */
icculus@7621
   280
    /*if (supported & SDL_HAPTIC_SQUARE)
icculus@7621
   281
        printf("      square\n");*/
slouken@2713
   282
    if (supported & SDL_HAPTIC_TRIANGLE)
slouken@2713
   283
        printf("      triangle\n");
slouken@2713
   284
    if (supported & SDL_HAPTIC_SAWTOOTHUP)
slouken@2713
   285
        printf("      sawtoothup\n");
slouken@2713
   286
    if (supported & SDL_HAPTIC_SAWTOOTHDOWN)
slouken@2713
   287
        printf("      sawtoothdown\n");
slouken@2713
   288
    if (supported & SDL_HAPTIC_RAMP)
slouken@2713
   289
        printf("      ramp\n");
slouken@2713
   290
    if (supported & SDL_HAPTIC_FRICTION)
slouken@2713
   291
        printf("      friction\n");
slouken@2713
   292
    if (supported & SDL_HAPTIC_SPRING)
slouken@2713
   293
        printf("      spring\n");
slouken@2713
   294
    if (supported & SDL_HAPTIC_DAMPER)
slouken@2713
   295
        printf("      damper\n");
slouken@2713
   296
    if (supported & SDL_HAPTIC_INERTIA)
slouken@2713
   297
        printf("      intertia\n");
slouken@2713
   298
    if (supported & SDL_HAPTIC_CUSTOM)
slouken@2713
   299
        printf("      custom\n");
icculus@7621
   300
    if (supported & SDL_HAPTIC_LEFTRIGHT)
icculus@7621
   301
        printf("      left/right\n");
slouken@2713
   302
    printf("   Supported capabilities:\n");
slouken@2713
   303
    if (supported & SDL_HAPTIC_GAIN)
slouken@2713
   304
        printf("      gain\n");
slouken@2713
   305
    if (supported & SDL_HAPTIC_AUTOCENTER)
slouken@2713
   306
        printf("      autocenter\n");
slouken@2713
   307
    if (supported & SDL_HAPTIC_STATUS)
slouken@2713
   308
        printf("      status\n");
slouken@2713
   309
}
aschiffler@6771
   310
aschiffler@6771
   311
#else
aschiffler@6771
   312
aschiffler@6771
   313
int
aschiffler@6771
   314
main(int argc, char *argv[])
aschiffler@6771
   315
{
aschiffler@6771
   316
    fprintf(stderr, "SDL compiled without Haptic support.\n");
aschiffler@6771
   317
    exit(1);
aschiffler@6771
   318
}
aschiffler@6771
   319
aschiffler@6771
   320
#endif