test/testgesture.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 23 Apr 2019 07:59:31 -0700
changeset 12714 9b7633bd0aa0
parent 12658 92e2b144d965
child 12732 0280fd2d02ca
permissions -rw-r--r--
Use _Exit() when available
slouken@5535
     1
/*
slouken@12503
     2
  Copyright (C) 1997-2019 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
*/
icculus@12635
    12
jim@4689
    13
/*  Usage:
jim@4689
    14
 *  Spacebar to begin recording a gesture on all touches.
jim@4689
    15
 *  s to save all touches into "./gestureSave"
jim@4689
    16
 *  l to load all touches from "./gestureSave"
jim@4689
    17
 */
jim@4689
    18
slouken@5456
    19
#include "SDL.h"
philipp@9590
    20
#include <stdlib.h> /* for exit() */
jim@4689
    21
icculus@9278
    22
#ifdef __EMSCRIPTEN__
icculus@9278
    23
#include <emscripten/emscripten.h>
icculus@9278
    24
#endif
icculus@9278
    25
icculus@12633
    26
#include "SDL_test.h"
icculus@12633
    27
#include "SDL_test_common.h"
icculus@12633
    28
jim@4689
    29
#define WIDTH 640
jim@4689
    30
#define HEIGHT 480
jim@4689
    31
#define BPP 4
jim@4689
    32
gabomdq@7678
    33
/* MUST BE A POWER OF 2! */
jim@4689
    34
#define EVENT_BUF_SIZE 256
jim@4689
    35
slouken@5458
    36
#define VERBOSE 0
jim@4689
    37
icculus@12633
    38
static SDLTest_CommonState *state;
slouken@5457
    39
static SDL_Event events[EVENT_BUF_SIZE];
slouken@5457
    40
static int eventWrite;
slouken@5457
    41
static int colors[7] = {0xFF,0xFF00,0xFF0000,0xFFFF00,0x00FFFF,0xFF00FF,0xFFFFFF};
icculus@12634
    42
static int quitting = 0;
icculus@9278
    43
icculus@12635
    44
typedef struct
icculus@12635
    45
{
icculus@12635
    46
    float x, y;
jim@4689
    47
} Point;
jim@4689
    48
icculus@12635
    49
typedef struct
icculus@12635
    50
{
icculus@12635
    51
    float ang, r;
icculus@12635
    52
    Point p;
jim@4689
    53
} Knob;
jim@4689
    54
icculus@12635
    55
static Knob knob = { 0.0f, 0.1f, { 0.0f, 0.0f } };
jim@4689
    56
icculus@12635
    57
icculus@12635
    58
static void
icculus@12635
    59
setpix(SDL_Surface *screen, float _x, float _y, unsigned int col)
jim@4689
    60
{
icculus@12635
    61
    Uint32 *pixmem32;
icculus@12635
    62
    Uint32 colour;
icculus@12635
    63
    Uint8 r, g, b;
icculus@12635
    64
    const int x = (int)_x;
icculus@12635
    65
    const int y = (int)_y;
icculus@12635
    66
    float a;
slouken@7191
    67
icculus@12635
    68
    if ( (x < 0) || (x >= screen->w) || (y < 0) || (y >= screen->h) ) {
icculus@12635
    69
        return;
icculus@12635
    70
    }
jim@4689
    71
icculus@12635
    72
    pixmem32 = (Uint32 *) screen->pixels + y * screen->pitch / BPP + x;
slouken@7191
    73
icculus@12635
    74
    SDL_memcpy(&colour, pixmem32, screen->format->BytesPerPixel);
jim@4689
    75
icculus@12635
    76
    SDL_GetRGB(colour,screen->format,&r,&g,&b);
slouken@7191
    77
icculus@12635
    78
    /* r = 0;g = 0; b = 0; */
icculus@12635
    79
    a = (float) ((col >> 24) & 0xFF);
icculus@12635
    80
    if (a == 0) {
icculus@12635
    81
        a = 0xFF; /* Hack, to make things easier. */
icculus@12635
    82
    }
jim@4689
    83
icculus@12635
    84
    a = (a == 0.0f) ? 1 : (a / 255.0f);
icculus@12635
    85
    r = (Uint8) (r * (1 - a) + ((col >> 16) & 0xFF) * a);
icculus@12635
    86
    g = (Uint8) (g * (1 - a) + ((col >> 8) & 0xFF) * a);
icculus@12635
    87
    b = (Uint8) (b * (1 - a) + ((col >> 0) & 0xFF) * a);
icculus@12635
    88
    colour = SDL_MapRGB(screen->format, r, g, b);
icculus@12635
    89
icculus@12635
    90
    *pixmem32 = colour;
jim@4689
    91
}
jim@4689
    92
icculus@12635
    93
static void
icculus@12635
    94
drawLine(SDL_Surface *screen, float x0, float y0, float x1, float y1, unsigned int col)
icculus@12635
    95
{
icculus@12635
    96
    float t;
icculus@12635
    97
    for (t = 0; t < 1; t += (float) (1.0f / SDL_max(SDL_fabs(x0 - x1), SDL_fabs(y0 - y1)))) {
icculus@12635
    98
        setpix(screen, x1 + t * (x0 - x1), y1 + t * (y0 - y1), col);
icculus@12635
    99
    }
jim@4689
   100
}
jim@4689
   101
icculus@12635
   102
static void
icculus@12635
   103
drawCircle(SDL_Surface *screen, float x, float y, float r, unsigned int c)
jim@4689
   104
{
icculus@12635
   105
    float tx,ty, xr;
icculus@12635
   106
    for (ty = (float) -SDL_fabs(r); ty <= (float) SDL_fabs((int) r); ty++) {
icculus@12635
   107
        xr = (float) SDL_sqrt(r * r - ty * ty);
icculus@12635
   108
        if (r > 0) { /* r > 0 ==> filled circle */
icculus@12635
   109
            for(tx = -xr + 0.5f; tx <= xr - 0.5f; tx++) {
icculus@12635
   110
                setpix(screen, x + tx, y + ty, c);
icculus@12635
   111
            }
icculus@12635
   112
        } else {
icculus@12635
   113
            setpix(screen, x - xr + 0.5f, y + ty, c);
icculus@12635
   114
            setpix(screen, x + xr - 0.5f, y + ty, c);
icculus@12635
   115
        }
jim@4689
   116
    }
jim@4689
   117
}
jim@4689
   118
icculus@12635
   119
static void
icculus@12635
   120
drawKnob(SDL_Surface *screen, const Knob *k)
icculus@12635
   121
{
icculus@12635
   122
    drawCircle(screen, k->p.x * screen->w, k->p.y * screen->h, k->r * screen->w, 0xFFFFFF);
icculus@12635
   123
    drawCircle(screen, (k->p.x + k->r / 2 * SDL_cosf(k->ang)) * screen->w,
icculus@12635
   124
               (k->p.y + k->r / 2 * SDL_sinf(k->ang)) * screen->h, k->r / 4 * screen->w, 0);
jim@4689
   125
}
jim@4689
   126
icculus@12635
   127
static void
icculus@12635
   128
DrawScreen(SDL_Window *window)
jim@4689
   129
{
icculus@12635
   130
    SDL_Surface *screen = SDL_GetWindowSurface(window);
icculus@12635
   131
    int i;
icculus@12633
   132
icculus@12635
   133
    if (!screen) {
icculus@12635
   134
        return;
icculus@12635
   135
    }
icculus@12633
   136
icculus@12658
   137
    SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 75, 75, 75));
jim@4689
   138
icculus@12635
   139
    /* draw Touch History */
icculus@12635
   140
    for (i = eventWrite; i < eventWrite + EVENT_BUF_SIZE; ++i) {
icculus@12635
   141
        const SDL_Event *event = &events[i & (EVENT_BUF_SIZE - 1)];
icculus@12635
   142
        const float age = (float)(i - eventWrite) / EVENT_BUF_SIZE;
icculus@12635
   143
        float x, y;
icculus@12635
   144
        unsigned int c, col;
slouken@4918
   145
icculus@12635
   146
        if ( (event->type == SDL_FINGERMOTION) ||
icculus@12635
   147
             (event->type == SDL_FINGERDOWN) ||
icculus@12635
   148
             (event->type == SDL_FINGERUP) ) {
icculus@12635
   149
            x = event->tfinger.x;
icculus@12635
   150
            y = event->tfinger.y;
slouken@7191
   151
icculus@12635
   152
            /* draw the touch: */
icculus@12635
   153
            c = colors[event->tfinger.fingerId % 7];
icculus@12635
   154
            col = ((unsigned int) (c * (0.1f + 0.85f))) | (unsigned int) (0xFF * age) << 24;
jim@4689
   155
icculus@12635
   156
            if (event->type == SDL_FINGERMOTION) {
icculus@12635
   157
                drawCircle(screen, x * screen->w, y * screen->h, 5, col);
icculus@12635
   158
            } else if (event->type == SDL_FINGERDOWN) {
icculus@12635
   159
                drawCircle(screen, x * screen->w, y * screen->h, -10, col);
icculus@12635
   160
            }
icculus@12635
   161
        }
jim@4689
   162
    }
slouken@7191
   163
icculus@12635
   164
    if (knob.p.x > 0) {
icculus@12635
   165
        drawKnob(screen, &knob);
icculus@12635
   166
    }
slouken@7191
   167
icculus@12635
   168
    SDL_UpdateWindowSurface(window);
jim@4689
   169
}
jim@4689
   170
icculus@12635
   171
static void
icculus@12635
   172
loop(void)
slouken@7191
   173
{
icculus@9278
   174
    SDL_Event event;
icculus@9278
   175
    SDL_RWops *stream;
icculus@12633
   176
    int i;
jim@4689
   177
icculus@12635
   178
    while (SDL_PollEvent(&event)) {
icculus@12633
   179
        SDLTest_CommonEvent(state, &event, &quitting);
icculus@12633
   180
icculus@12635
   181
        /* Record _all_ events */
icculus@12635
   182
        events[eventWrite & (EVENT_BUF_SIZE-1)] = event;
icculus@12635
   183
        eventWrite++;
slouken@7191
   184
icculus@12635
   185
        switch (event.type) {
icculus@12635
   186
            case SDL_KEYDOWN:
icculus@12635
   187
                switch (event.key.keysym.sym) {
icculus@12635
   188
                    case SDLK_i: {
icculus@12635
   189
                        for (i = 0; i < SDL_GetNumTouchDevices(); ++i) {
icculus@12635
   190
                            const SDL_TouchID id = SDL_GetTouchDevice(i);
icculus@12635
   191
                            SDL_Log("Fingers Down on device %"SDL_PRIs64": %d", id, SDL_GetNumTouchFingers(id));
icculus@12635
   192
                        }
icculus@12635
   193
                        break;
icculus@12635
   194
                    }
icculus@12635
   195
icculus@12635
   196
                    case SDLK_SPACE:
icculus@12635
   197
                        SDL_RecordGesture(-1);
icculus@12635
   198
                        break;
icculus@12635
   199
icculus@12635
   200
                    case SDLK_s:
icculus@12635
   201
                        stream = SDL_RWFromFile("gestureSave", "w");
icculus@12635
   202
                        SDL_Log("Wrote %i templates", SDL_SaveAllDollarTemplates(stream));
icculus@12635
   203
                        SDL_RWclose(stream);
icculus@12635
   204
                        break;
icculus@12635
   205
icculus@12635
   206
                    case SDLK_l:
icculus@12635
   207
                        stream = SDL_RWFromFile("gestureSave", "r");
icculus@12635
   208
                        SDL_Log("Loaded: %i", SDL_LoadDollarTemplates(-1, stream));
icculus@12635
   209
                        SDL_RWclose(stream);
icculus@12635
   210
                        break;
icculus@12635
   211
                }
icculus@12635
   212
                break;
icculus@12635
   213
icculus@12635
   214
#if VERBOSE
icculus@12635
   215
            case SDL_FINGERMOTION:
icculus@12635
   216
                SDL_Log("Finger: %"SDL_PRIs64",x: %f, y: %f",event.tfinger.fingerId,
icculus@12635
   217
                        event.tfinger.x,event.tfinger.y);
icculus@12635
   218
                break;
icculus@12635
   219
icculus@12635
   220
            case SDL_FINGERDOWN:
icculus@12635
   221
                SDL_Log("Finger: %"SDL_PRIs64" down - x: %f, y: %f",
icculus@12635
   222
                        event.tfinger.fingerId,event.tfinger.x,event.tfinger.y);
icculus@12635
   223
                break;
icculus@12635
   224
icculus@12635
   225
            case SDL_FINGERUP:
icculus@12635
   226
                SDL_Log("Finger: %"SDL_PRIs64" up - x: %f, y: %f",
icculus@12635
   227
                        event.tfinger.fingerId,event.tfinger.x,event.tfinger.y);
icculus@12635
   228
                break;
icculus@12635
   229
#endif
icculus@12635
   230
icculus@12635
   231
            case SDL_MULTIGESTURE:
icculus@12635
   232
#if VERBOSE
icculus@12635
   233
                SDL_Log("Multi Gesture: x = %f, y = %f, dAng = %f, dR = %f",
icculus@12635
   234
                        event.mgesture.x, event.mgesture.y,
icculus@12635
   235
                        event.mgesture.dTheta, event.mgesture.dDist);
icculus@12635
   236
                SDL_Log("MG: numDownTouch = %i",event.mgesture.numFingers);
icculus@12635
   237
#endif
icculus@12635
   238
icculus@12635
   239
                knob.p.x = event.mgesture.x;
icculus@12635
   240
                knob.p.y = event.mgesture.y;
icculus@12635
   241
                knob.ang += event.mgesture.dTheta;
icculus@12635
   242
                knob.r += event.mgesture.dDist;
icculus@12635
   243
                break;
icculus@12635
   244
icculus@12635
   245
            case SDL_DOLLARGESTURE:
icculus@12635
   246
                SDL_Log("Gesture %"SDL_PRIs64" performed, error: %f",
icculus@12635
   247
                        event.dgesture.gestureId, event.dgesture.error);
icculus@12635
   248
                break;
icculus@12635
   249
icculus@12635
   250
            case SDL_DOLLARRECORD:
icculus@12635
   251
                SDL_Log("Recorded gesture: %"SDL_PRIs64"",event.dgesture.gestureId);
icculus@12635
   252
                break;
slouken@7191
   253
        }
icculus@9278
   254
    }
icculus@12633
   255
icculus@12633
   256
    for (i = 0; i < state->num_windows; ++i) {
icculus@12633
   257
        if (state->windows[i]) {
icculus@12635
   258
            DrawScreen(state->windows[i]);
icculus@12633
   259
        }
icculus@12633
   260
    }
philipp@9607
   261
philipp@9607
   262
#ifdef __EMSCRIPTEN__
philipp@9607
   263
    if (quitting) {
philipp@9607
   264
        emscripten_cancel_main_loop();
philipp@9607
   265
    }
philipp@9607
   266
#endif
icculus@9278
   267
}
icculus@9278
   268
icculus@9278
   269
int main(int argc, char* argv[])
icculus@9278
   270
{
icculus@12635
   271
    int i;
icculus@9278
   272
icculus@12635
   273
    /* !!! FIXME: there should be an SDLTest_CommonDefaultArgs() so apps don't need this. */
icculus@12635
   274
    state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
icculus@12635
   275
    if (!state) {
icculus@12635
   276
        return 1;
icculus@12635
   277
    }
icculus@9278
   278
icculus@12635
   279
    state->window_title = "Gesture Test";
icculus@12635
   280
    state->window_w = WIDTH;
icculus@12635
   281
    state->window_h = HEIGHT;
icculus@12635
   282
    state->skip_renderer = SDL_TRUE;
icculus@12633
   283
icculus@12635
   284
    for (i = 1; i < argc;) {
icculus@12635
   285
        const int consumed = SDLTest_CommonArg(state, i);
icculus@12635
   286
        if (consumed == 0) {
icculus@12635
   287
            SDL_Log("Usage: %s %s\n", argv[0], SDLTest_CommonUsage(state));
icculus@12635
   288
            return 1;
icculus@12635
   289
        }
icculus@12635
   290
        i += consumed;
icculus@12633
   291
    }
icculus@12633
   292
icculus@12635
   293
    if (!SDLTest_CommonInit(state)) {
icculus@12635
   294
        return 1;
icculus@12635
   295
    }
icculus@9289
   296
icculus@9278
   297
#ifdef __EMSCRIPTEN__
icculus@9278
   298
    emscripten_set_main_loop(loop, 0, 1);
icculus@9278
   299
#else
icculus@12635
   300
    while (!quitting) {
icculus@9278
   301
        loop();
icculus@9278
   302
    }
icculus@9278
   303
#endif
icculus@9278
   304
icculus@12635
   305
    SDLTest_CommonQuit(state);
icculus@12635
   306
    return 0;
jim@4689
   307
}
jim@4689
   308