mirror of
				https://github.com/libsdl-org/SDL.git
				synced 2025-11-04 09:44:35 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			301 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			301 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
 | 
						|
 | 
						|
  This software is provided 'as-is', without any express or implied
 | 
						|
  warranty.  In no event will the authors be held liable for any damages
 | 
						|
  arising from the use of this software.
 | 
						|
 | 
						|
  Permission is granted to anyone to use this software for any purpose,
 | 
						|
  including commercial applications, and to alter it and redistribute it
 | 
						|
  freely.
 | 
						|
*/
 | 
						|
 | 
						|
/*  Usage:
 | 
						|
 *  Spacebar to begin recording a gesture on all touches.
 | 
						|
 *  s to save all touches into "./gestureSave"
 | 
						|
 *  l to load all touches from "./gestureSave"
 | 
						|
 */
 | 
						|
 | 
						|
#include "SDL.h"
 | 
						|
#include <stdlib.h> /* for exit() */
 | 
						|
 | 
						|
#ifdef __EMSCRIPTEN__
 | 
						|
#include <emscripten/emscripten.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include "SDL_test.h"
 | 
						|
#include "SDL_test_common.h"
 | 
						|
 | 
						|
#define WIDTH 640
 | 
						|
#define HEIGHT 480
 | 
						|
#define BPP 4
 | 
						|
 | 
						|
/* MUST BE A POWER OF 2! */
 | 
						|
#define EVENT_BUF_SIZE 256
 | 
						|
 | 
						|
#define VERBOSE 0
 | 
						|
 | 
						|
static SDLTest_CommonState *state;
 | 
						|
static SDL_Event events[EVENT_BUF_SIZE];
 | 
						|
static int eventWrite;
 | 
						|
static int colors[7] = {0xFF,0xFF00,0xFF0000,0xFFFF00,0x00FFFF,0xFF00FF,0xFFFFFF};
 | 
						|
static int quitting = 0;
 | 
						|
 | 
						|
typedef struct
 | 
						|
{
 | 
						|
    float x, y;
 | 
						|
} Point;
 | 
						|
 | 
						|
typedef struct
 | 
						|
{
 | 
						|
    float ang, r;
 | 
						|
    Point p;
 | 
						|
} Knob;
 | 
						|
 | 
						|
static Knob knob = { 0.0f, 0.1f, { 0.0f, 0.0f } };
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
setpix(SDL_Surface *screen, float _x, float _y, unsigned int col)
 | 
						|
{
 | 
						|
    Uint32 *pixmem32;
 | 
						|
    Uint32 colour;
 | 
						|
    Uint8 r, g, b;
 | 
						|
    const int x = (int)_x;
 | 
						|
    const int y = (int)_y;
 | 
						|
    float a;
 | 
						|
 | 
						|
    if ( (x < 0) || (x >= screen->w) || (y < 0) || (y >= screen->h) ) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    pixmem32 = (Uint32 *) screen->pixels + y * screen->pitch / BPP + x;
 | 
						|
 | 
						|
    SDL_memcpy(&colour, pixmem32, screen->format->BytesPerPixel);
 | 
						|
 | 
						|
    SDL_GetRGB(colour,screen->format,&r,&g,&b);
 | 
						|
 | 
						|
    /* r = 0;g = 0; b = 0; */
 | 
						|
    a = (float) ((col >> 24) & 0xFF);
 | 
						|
    if (a == 0) {
 | 
						|
        a = 0xFF; /* Hack, to make things easier. */
 | 
						|
    }
 | 
						|
 | 
						|
    a = (a == 0.0f) ? 1 : (a / 255.0f);
 | 
						|
    r = (Uint8) (r * (1 - a) + ((col >> 16) & 0xFF) * a);
 | 
						|
    g = (Uint8) (g * (1 - a) + ((col >> 8) & 0xFF) * a);
 | 
						|
    b = (Uint8) (b * (1 - a) + ((col >> 0) & 0xFF) * a);
 | 
						|
    colour = SDL_MapRGB(screen->format, r, g, b);
 | 
						|
 | 
						|
    *pixmem32 = colour;
 | 
						|
}
 | 
						|
 | 
						|
#if 0 /* unused */
 | 
						|
static void
 | 
						|
drawLine(SDL_Surface *screen, float x0, float y0, float x1, float y1, unsigned int col)
 | 
						|
{
 | 
						|
    float t;
 | 
						|
    for (t = 0; t < 1; t += (float) (1.0f / SDL_max(SDL_fabs(x0 - x1), SDL_fabs(y0 - y1)))) {
 | 
						|
        setpix(screen, x1 + t * (x0 - x1), y1 + t * (y0 - y1), col);
 | 
						|
    }
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
static void
 | 
						|
drawCircle(SDL_Surface *screen, float x, float y, float r, unsigned int c)
 | 
						|
{
 | 
						|
    float tx,ty, xr;
 | 
						|
    for (ty = (float) -SDL_fabs(r); ty <= (float) SDL_fabs((int) r); ty++) {
 | 
						|
        xr = (float) SDL_sqrt(r * r - ty * ty);
 | 
						|
        if (r > 0) { /* r > 0 ==> filled circle */
 | 
						|
            for(tx = -xr + 0.5f; tx <= xr - 0.5f; tx++) {
 | 
						|
                setpix(screen, x + tx, y + ty, c);
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            setpix(screen, x - xr + 0.5f, y + ty, c);
 | 
						|
            setpix(screen, x + xr - 0.5f, y + ty, c);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
drawKnob(SDL_Surface *screen, const Knob *k)
 | 
						|
{
 | 
						|
    drawCircle(screen, k->p.x * screen->w, k->p.y * screen->h, k->r * screen->w, 0xFFFFFF);
 | 
						|
    drawCircle(screen, (k->p.x + k->r / 2 * SDL_cosf(k->ang)) * screen->w,
 | 
						|
               (k->p.y + k->r / 2 * SDL_sinf(k->ang)) * screen->h, k->r / 4 * screen->w, 0);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
DrawScreen(SDL_Window *window)
 | 
						|
{
 | 
						|
    SDL_Surface *screen = SDL_GetWindowSurface(window);
 | 
						|
    int i;
 | 
						|
 | 
						|
    if (!screen) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 75, 75, 75));
 | 
						|
 | 
						|
    /* draw Touch History */
 | 
						|
    for (i = eventWrite; i < eventWrite + EVENT_BUF_SIZE; ++i) {
 | 
						|
        const SDL_Event *event = &events[i & (EVENT_BUF_SIZE - 1)];
 | 
						|
        const float age = (float)(i - eventWrite) / EVENT_BUF_SIZE;
 | 
						|
        float x, y;
 | 
						|
        unsigned int c, col;
 | 
						|
 | 
						|
        if ( (event->type == SDL_FINGERMOTION) ||
 | 
						|
             (event->type == SDL_FINGERDOWN) ||
 | 
						|
             (event->type == SDL_FINGERUP) ) {
 | 
						|
            x = event->tfinger.x;
 | 
						|
            y = event->tfinger.y;
 | 
						|
 | 
						|
            /* draw the touch: */
 | 
						|
            c = colors[event->tfinger.fingerId % 7];
 | 
						|
            col = ((unsigned int) (c * (0.1f + 0.85f))) | (unsigned int) (0xFF * age) << 24;
 | 
						|
 | 
						|
            if (event->type == SDL_FINGERMOTION) {
 | 
						|
                drawCircle(screen, x * screen->w, y * screen->h, 5, col);
 | 
						|
            } else if (event->type == SDL_FINGERDOWN) {
 | 
						|
                drawCircle(screen, x * screen->w, y * screen->h, -10, col);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (knob.p.x > 0) {
 | 
						|
        drawKnob(screen, &knob);
 | 
						|
    }
 | 
						|
 | 
						|
    SDL_UpdateWindowSurface(window);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
loop(void)
 | 
						|
{
 | 
						|
    SDL_Event event;
 | 
						|
    SDL_RWops *stream;
 | 
						|
    int i;
 | 
						|
 | 
						|
    while (SDL_PollEvent(&event)) {
 | 
						|
        SDLTest_CommonEvent(state, &event, &quitting);
 | 
						|
 | 
						|
        /* Record _all_ events */
 | 
						|
        events[eventWrite & (EVENT_BUF_SIZE-1)] = event;
 | 
						|
        eventWrite++;
 | 
						|
 | 
						|
        switch (event.type) {
 | 
						|
            case SDL_KEYDOWN:
 | 
						|
                switch (event.key.keysym.sym) {
 | 
						|
                    case SDLK_i: {
 | 
						|
                        for (i = 0; i < SDL_GetNumTouchDevices(); ++i) {
 | 
						|
                            const SDL_TouchID id = SDL_GetTouchDevice(i);
 | 
						|
                            const char *name = SDL_GetTouchName(i);
 | 
						|
                            SDL_Log("Fingers Down on device %"SDL_PRIs64" (%s): %d", id, name, SDL_GetNumTouchFingers(id));
 | 
						|
                        }
 | 
						|
                        break;
 | 
						|
                    }
 | 
						|
 | 
						|
                    case SDLK_SPACE:
 | 
						|
                        SDL_RecordGesture(-1);
 | 
						|
                        break;
 | 
						|
 | 
						|
                    case SDLK_s:
 | 
						|
                        stream = SDL_RWFromFile("gestureSave", "w");
 | 
						|
                        SDL_Log("Wrote %i templates", SDL_SaveAllDollarTemplates(stream));
 | 
						|
                        SDL_RWclose(stream);
 | 
						|
                        break;
 | 
						|
 | 
						|
                    case SDLK_l:
 | 
						|
                        stream = SDL_RWFromFile("gestureSave", "r");
 | 
						|
                        SDL_Log("Loaded: %i", SDL_LoadDollarTemplates(-1, stream));
 | 
						|
                        SDL_RWclose(stream);
 | 
						|
                        break;
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
#if VERBOSE
 | 
						|
            case SDL_FINGERMOTION:
 | 
						|
                SDL_Log("Finger: %"SDL_PRIs64", x: %f, y: %f",event.tfinger.fingerId,
 | 
						|
                        event.tfinger.x,event.tfinger.y);
 | 
						|
                break;
 | 
						|
 | 
						|
            case SDL_FINGERDOWN:
 | 
						|
                SDL_Log("Finger: %"SDL_PRIs64" down - x: %f, y: %f",
 | 
						|
                        event.tfinger.fingerId,event.tfinger.x,event.tfinger.y);
 | 
						|
                break;
 | 
						|
 | 
						|
            case SDL_FINGERUP:
 | 
						|
                SDL_Log("Finger: %"SDL_PRIs64" up - x: %f, y: %f",
 | 
						|
                        event.tfinger.fingerId,event.tfinger.x,event.tfinger.y);
 | 
						|
                break;
 | 
						|
#endif
 | 
						|
 | 
						|
            case SDL_MULTIGESTURE:
 | 
						|
#if VERBOSE
 | 
						|
                SDL_Log("Multi Gesture: x = %f, y = %f, dAng = %f, dR = %f",
 | 
						|
                        event.mgesture.x, event.mgesture.y,
 | 
						|
                        event.mgesture.dTheta, event.mgesture.dDist);
 | 
						|
                SDL_Log("MG: numDownTouch = %i",event.mgesture.numFingers);
 | 
						|
#endif
 | 
						|
 | 
						|
                knob.p.x = event.mgesture.x;
 | 
						|
                knob.p.y = event.mgesture.y;
 | 
						|
                knob.ang += event.mgesture.dTheta;
 | 
						|
                knob.r += event.mgesture.dDist;
 | 
						|
                break;
 | 
						|
 | 
						|
            case SDL_DOLLARGESTURE:
 | 
						|
                SDL_Log("Gesture %"SDL_PRIs64" performed, error: %f",
 | 
						|
                        event.dgesture.gestureId, event.dgesture.error);
 | 
						|
                break;
 | 
						|
 | 
						|
            case SDL_DOLLARRECORD:
 | 
						|
                SDL_Log("Recorded gesture: %"SDL_PRIs64"",event.dgesture.gestureId);
 | 
						|
                break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; i < state->num_windows; ++i) {
 | 
						|
        if (state->windows[i]) {
 | 
						|
            DrawScreen(state->windows[i]);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
#ifdef __EMSCRIPTEN__
 | 
						|
    if (quitting) {
 | 
						|
        emscripten_cancel_main_loop();
 | 
						|
    }
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
int main(int argc, char* argv[])
 | 
						|
{
 | 
						|
    state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
 | 
						|
    if (!state) {
 | 
						|
        return 1;
 | 
						|
    }
 | 
						|
 | 
						|
    state->window_title = "Gesture Test";
 | 
						|
    state->window_w = WIDTH;
 | 
						|
    state->window_h = HEIGHT;
 | 
						|
    state->skip_renderer = SDL_TRUE;
 | 
						|
 | 
						|
    if (!SDLTest_CommonDefaultArgs(state, argc, argv) || !SDLTest_CommonInit(state)) {
 | 
						|
        SDLTest_CommonQuit(state);
 | 
						|
        return 1;
 | 
						|
    }
 | 
						|
 | 
						|
#ifdef __EMSCRIPTEN__
 | 
						|
    emscripten_set_main_loop(loop, 0, 1);
 | 
						|
#else
 | 
						|
    while (!quitting) {
 | 
						|
        loop();
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
    SDLTest_CommonQuit(state);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 |