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