Joystick support
authorAndreas Eversberg <jolly@eversberg.eu>
Sun, 7 Apr 2019 07:26:11 +0000 (09:26 +0200)
committerAndreas Eversberg <jolly@eversberg.eu>
Sun, 7 Apr 2019 07:42:44 +0000 (09:42 +0200)
src/libsdl/sdl.c
src/libsdl/sdl.h
src/mercenary/main.c

index 804695c..b10efec 100644 (file)
@@ -34,9 +34,12 @@ static const char *device_string = NULL;
 static SDL_AudioDeviceID audio_devid = 0;
 static SDL_Window *gl_window = NULL;
 static SDL_GLContext gl_context = NULL;
+static SDL_Joystick *sdl_joystick = NULL;
 static void (*keyboard_sdl)(int down, enum keycode keycode) = NULL;
+static void (*joystick_sdl)(double x, double y, int fire) = NULL;
 static void (*audio_sdl)(float *data, int len) = NULL;
 static void (*resize_window_sdl)(int width, int height) = NULL;
+static int joystick_y_axis_sdl = 1, joystick_x_axis_sdl = 0, joystick_fire_button_sdl = -1;
 
 static void audio_cb(void __attribute__((unused)) *userdata, Uint8 *stream, int len)
 {
@@ -47,22 +50,54 @@ static void audio_cb(void __attribute__((unused)) *userdata, Uint8 *stream, int
        SDL_MixAudioFormat(stream, (Uint8 *)audio_data, AUDIO_F32, len, SDL_MIX_MAXVOLUME / 2.0);
 }
 
-int init_sdl(const char *progname, int width, int height, int sound_samplerate, int sound_chunk, void (*keyboard)(int down, enum keycode keycode), void (*audio)(float *data, int len), void (*resize_window)(int width, int height), int multisampling, int vbl_sync, int rift)
+void sdl_list_joysticks(void)
 {
-       int rc;
+       int num, i, rc;
+
+       rc = SDL_Init(SDL_INIT_JOYSTICK);
+       if (rc < 0) {
+               print_error("Failed to init SDL\n");
+               return;
+       }
+
+       num = SDL_NumJoysticks();
+       for (i = 0; i < num; i++)
+               printf("#%d: %s\n", i, SDL_JoystickNameForIndex(i));
+
+       SDL_Quit();
+}
+
+int init_sdl(const char *progname, int width, int height, int sound_samplerate, int sound_chunk, void (*keyboard)(int down, enum keycode keycode), int joysticknum, int joystick_x_axis, int joystick_y_axis, int joystick_fire_button, void (*joystick)(double x, double y, int fire), void (*audio)(float *data, int len), void (*resize_window)(int width, int height), int multisampling, int vbl_sync, int rift)
+{
+       int rc = -EINVAL;
 
        keyboard_sdl = keyboard;
+       joystick_sdl = joystick;
        audio_sdl = audio;
        resize_window_sdl = resize_window;
+       if (joystick_x_axis >= 0)
+               joystick_x_axis_sdl = joystick_x_axis;
+       if (joystick_y_axis >= 0)
+               joystick_y_axis_sdl = joystick_y_axis;
+       if (joystick_fire_button >= 0)
+               joystick_fire_button_sdl = joystick_fire_button;
 
        /* init SDL library */
-       rc = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
+       rc = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK);
        if (rc < 0) {
                print_error("Failed to init SDL\n");
                goto error;
        }
        sdl_initialized = 1;
 
+       SDL_JoystickEventState(SDL_ENABLE);
+       sdl_joystick = SDL_JoystickOpen((joysticknum < 0) ? 0 : joysticknum);
+       if (!sdl_joystick && joysticknum >= 0) {
+               rc = -EIO;
+               print_error("Failed to open joystick #%d, see help!\n", joysticknum);
+               goto error;
+       }
+
 retry_without_multisampling:
        if (multisampling > 1) {
                SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
@@ -285,6 +320,22 @@ static enum keycode sdl2keycode(SDL_Keycode sym)
        }
 }
 
+static double joystick_x = 0, joystick_y = 0;
+static int joystick_fire = 0;
+
+static void joystick_event(int axis, int value)
+{
+       double v = (double)value  / 32767.0;
+
+       switch (axis) {
+       case 0: joystick_y = v; break;
+       case 1: joystick_x = v; break;
+       case 2: joystick_fire = value; break;
+       }
+
+       joystick_sdl(joystick_x, joystick_y, joystick_fire);
+}
+
 static int key_ctrl = 0, key_f = 0, fullscreen = 0;
 
 int event_sdl(void)
@@ -293,13 +344,15 @@ int event_sdl(void)
        SDL_Event event;
 
        while (SDL_PollEvent(&event)) {
-               if (event.type == SDL_QUIT)
+               switch (event.type) {
+               case SDL_QUIT:
                        quit = 1;
-               if (event.type == SDL_WINDOWEVENT) {
+                       break;
+               case SDL_WINDOWEVENT:
                        if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
                                resize_window_sdl(event.window.data1, event.window.data2);
-               }
-               if (event.type == SDL_KEYDOWN) {
+                       break;
+               case SDL_KEYDOWN:
                        switch (event.key.keysym.sym) {
                        case SDLK_f:
                                if (key_ctrl && !key_f) {
@@ -321,8 +374,8 @@ int event_sdl(void)
                                break;
                        }
                        keyboard_sdl(1, sdl2keycode(event.key.keysym.sym));
-               }
-               if (event.type == SDL_KEYUP) {
+                       break;
+               case SDL_KEYUP:
                        switch (event.key.keysym.sym) {
                        case SDLK_LCTRL:
                        case SDLK_RCTRL:
@@ -333,6 +386,21 @@ int event_sdl(void)
                                break;
                        }
                        keyboard_sdl(0, sdl2keycode(event.key.keysym.sym));
+                       break;
+               case SDL_JOYAXISMOTION:
+                       if (event.jaxis.axis == joystick_y_axis_sdl)
+                               joystick_event(0, event.jaxis.value);
+                       if (event.jaxis.axis == joystick_x_axis_sdl)
+                               joystick_event(1, event.jaxis.value);
+                       break;
+               case SDL_JOYBUTTONDOWN:
+                       if (joystick_fire_button_sdl < 0 || event.jbutton.button == joystick_fire_button_sdl)
+                               joystick_event(2, 1);
+                       break;
+               case SDL_JOYBUTTONUP:
+                       if (joystick_fire_button_sdl < 0 || event.jbutton.button == joystick_fire_button_sdl)
+                               joystick_event(2, 0);
+                       break;
                }
        }
 
@@ -346,6 +414,11 @@ void swap_sdl(void)
 
 void exit_sdl(void)
 {
+       /* close joystick */
+       if (sdl_joystick) {
+               SDL_JoystickClose(sdl_joystick);
+               sdl_joystick = NULL;
+       }
        /* close window */
        if (gl_window) {
                SDL_DestroyWindow(gl_window);
index 7307496..cae8ff9 100644 (file)
@@ -1,5 +1,6 @@
 
-int init_sdl(const char *progname, int width, int height, int sound_samplerate, int sound_chunk, void (*keyboard)(int down, enum keycode keycode), void (*audio)(float *data, int len), void (*resize_window)(int width, int height), int multisampling, int vbl_sync, int rift);
+void sdl_list_joysticks(void);
+int init_sdl(const char *progname, int width, int height, int sound_samplerate, int sound_chunk, void (*keyboard)(int down, enum keycode keycode), int joysticknum, int joystick_x_axis, int joystick_y_axis, int joysytick_fire_button, void (*joystick)(double x, double y, int fire), void (*audio)(float *data, int len), void (*resize_window)(int width, int height), int multisampling, int vbl_sync, int rift);
 int event_sdl(void);
 void swap_sdl(void);
 void exit_sdl(void);
index 6931b29..d4ac4ee 100644 (file)
@@ -64,6 +64,7 @@ static int config_audio_filter = 1;
 static int config_render = 1; /* opengl render */
 static int config_skip_intro = 0;
 static int config_multisampling = 8;
+static int config_joystick = -1, config_joystick_x = -1, config_joystick_y = -1, config_joystick_fire = -1;
 #ifdef HAVE_OVR
 static double config_benson_size = 0.7;
 static double config_fov = FOV_JOLLY;
@@ -171,6 +172,12 @@ int parse_args(int argc, char *argv[])
                        print_info("        Set field-of-view. Default is %.0f.\n", FOV_NOVAGEN);
                        print_info(" -i --skip-intro\n");
                        print_info("        Skip intro sequence approaching to Eris space port.\n");
+                       print_info(" -j --joystick <num> | list\n");
+                       print_info("        Select given joystick number or show list. (default = 0, if available)\n");
+                       print_info("    --joystick-x <axis num>\n");
+                       print_info("    --joystick-y <axis num>\n");
+                       print_info("    --joystick-fire <button num>\n");
+                       print_info("        Specify explicit axis and button of joystick.\n");
                        print_info("Improvement options:\n");
                        print_info("    --extend-roads 1 | 0\n");
                        print_info("        Roads in the distance end in a single point. This was ok for low\n");
@@ -295,6 +302,34 @@ illegal_parameter:
                if (!strcmp(argv[i], "-i") || !strcmp(argv[i], "--skip-intro")) {
                        config_skip_intro = 1;
                } else
+               if (!strcmp(argv[i], "-j") || !strcmp(argv[i], "--joystick")) {
+                       i++;
+                       if (argc == i)
+                               goto missing_parameter;
+                       if (!strcmp(argv[i], "list")) {
+                               sdl_list_joysticks();
+                               return 1;
+                       }
+                       config_joystick = atoi(argv[i]);
+               } else
+               if (!strcmp(argv[i], "--joystick-x")) {
+                       i++;
+                       if (argc == i)
+                               goto missing_parameter;
+                       config_joystick_x = atoi(argv[i]);
+               } else
+               if (!strcmp(argv[i], "--joystick-y")) {
+                       i++;
+                       if (argc == i)
+                               goto missing_parameter;
+                       config_joystick_y = atoi(argv[i]);
+               } else
+               if (!strcmp(argv[i], "--joystick-fire")) {
+                       i++;
+                       if (argc == i)
+                               goto missing_parameter;
+                       config_joystick_fire = atoi(argv[i]);
+               } else
                if (!strcmp(argv[i], "--extend-roads")) {
                        i++;
                        if (argc == i)
@@ -1309,6 +1344,35 @@ static void keyboard_sdl(int down, enum keycode keycode)
        }
 }
 
+static double joystick_last_x = 0, joystick_last_y = 0;
+static int joystick_last_fire = 0;
+
+static void joystick_sdl(double x, double y, int fire)
+{
+       int left = -1, right = -1, up = -1, down = -1;
+
+       if (x <= -0.5 && joystick_last_x > -0.5)
+               left = 1;
+       if (x > -0.5 && joystick_last_x <= -0.5)
+               left = 0;
+       if (x >= 0.5 && joystick_last_x < 0.5)
+               right = 1;
+       if (x < 0.5 && joystick_last_x >= 0.5)
+               right = 0;
+       if (y <= -0.5 && joystick_last_y > -0.5)
+               up = 1;
+       if (y > -0.5 && joystick_last_y <= -0.5)
+               up = 0;
+       if (y >= 0.5 && joystick_last_y < 0.5)
+               down = 1;
+       if (y < 0.5 && joystick_last_y >= 0.5)
+               down = 0;
+       set_joystick(left, right, up, down, fire);
+       joystick_last_x = x;
+       joystick_last_y = y;
+       joystick_last_fire = fire;
+}
+
 void audio_sdl(float *data, int length)
 {
        int fill, s;
@@ -1432,7 +1496,7 @@ int main(int argc, char *argv[])
        window_width = (config_debug_opengl) ? SCREEN_WIDTH / 3 * 2 : SCREEN_WIDTH;
        window_height = (config_debug_opengl) ? SCREEN_HEIGHT / 3 * 4 : SCREEN_HEIGHT;
 #endif
-       rc = init_sdl(argv[0], window_width, window_height, SOUND_SAMPLERATE, sdl_sound_chunk, keyboard_sdl, audio_sdl, resize_window, multisampling, vbl_sync, vr);
+       rc = init_sdl(argv[0], window_width, window_height, SOUND_SAMPLERATE, sdl_sound_chunk, keyboard_sdl, config_joystick, config_joystick_x, config_joystick_y, config_joystick_fire, joystick_sdl, audio_sdl, resize_window, multisampling, vbl_sync, vr);
        if (rc < 0)
                goto done;
 #ifdef HAVE_OVR