commit 4b9272c4f291493e3d4bbd94eb1217a88475e88f
parent d0b952b2cdbb7ceff03c2c9a87b3eb95341a6535
Author: William Casarin <jb55@jb55.com>
Date:   Mon, 27 Apr 2020 01:10:48 -0700
input: initial controller support
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
5 files changed, 101 insertions(+), 31 deletions(-)
diff --git a/src/game.c b/src/game.c
@@ -25,10 +25,16 @@ mat4 *cam_init = (float[16]){
   -71.766136, -47.881512, -44.216671, 1.000000
 };
 
-int was_key_pressed_this_frame(struct game *game, int scancode) {
+bool was_key_pressed_this_frame(struct game *game, int scancode)
+{
     return is_key_down_on_frame(&game->input, scancode, game->frame);
 }
 
+bool was_button_pressed_this_frame(struct game *game, SDL_GameControllerButton button)
+{
+    return is_button_down_on_frame(&game->input, button, game->frame);
+}
+
 static void camera_update(struct node *node) {
   mat4 *persp = (float*)node->custom_update_data;
   mat4 *mat = (float*)node->mat;
@@ -58,7 +64,7 @@ static void init_user_settings(struct user_settings *settings) {
 
 static void init_sdl(SDL_Window **window, int width, int height)
 {
-    /* SDL_Init( SDL_INIT_VIDEO ); */
+    SDL_Init( SDL_INIT_JOYSTICK );
 
     /* SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); */
 
@@ -73,18 +79,8 @@ void quit_game(struct game *game)
     game->quit = 1;
 }
 
-void game_init(struct game *game, int width, int height) {
-    init_sdl(&game->window, width, height);
-    init_gl(&game->test_resources, width, height);
-    init_entity_system();
-    init_geometry_manager();
-    init_model_manager();
-    init_node_manager();
-    init_user_settings(&game->user_settings);
-    check_gl();
-
-    game->wireframe = 0;
-
+// TODO: cleanup
+void init_misc(struct game *game, int width, int height) {
     struct resources *res = &game->test_resources;
     mat4 *mvp = res->test_mvp;
 
@@ -209,3 +205,42 @@ void game_init(struct game *game, int width, int height) {
     // TEXTURES
     // END TEXTURES
 }
+
+void init_controller(struct input *input) {
+    SDL_GameControllerAddMappingsFromFile("data/gamecontrollerdb.txt");
+
+    int joysticks = SDL_NumJoysticks();
+    SDL_GameController *controller = NULL;
+
+    printf("Found %d joysticks\n", joysticks);
+
+    for (int i = 0; i < joysticks; i++) {
+        if (SDL_IsGameController(i)) {
+            controller = SDL_GameControllerOpen(i);
+            if (controller) {
+                printf("Found a game controller\n");
+                input->controller = controller;
+                break;
+            }
+        } else {
+            printf("Could not open game controller %d: %s\n", i, SDL_GetError());
+        }
+    }
+}
+
+void game_init(struct game *game, int width, int height) {
+    init_sdl(&game->window, width, height);
+    init_gl(&game->test_resources, width, height);
+    init_entity_system();
+    init_geometry_manager();
+    init_model_manager();
+    init_node_manager();
+    init_user_settings(&game->user_settings);
+
+    check_gl();
+
+    game->wireframe = 0;
+
+    init_controller(&game->input);
+    init_misc(game, width, height);
+}
diff --git a/src/game.h b/src/game.h
@@ -103,7 +103,8 @@ struct entity *get_terrain_entity(struct terrain *);
 void game_init(struct game *game, int width, int height);
 void quit_game(struct game *game);
 void should_update(struct game *game);
-int was_key_pressed_this_frame(struct game *game, int scancode);
+bool was_key_pressed_this_frame(struct game *game, int scancode);
+bool was_button_pressed_this_frame(struct game *game, SDL_GameControllerButton button);
 int is_free_camera(struct game *game);
 
 #endif /* PA_GAME_H */
diff --git a/src/input.c b/src/input.c
@@ -7,7 +7,7 @@
 static void key_down(struct input *input, int scancode, u64 current_frame) {
     input->modifiers = SDL_GetModState();
 
-    struct key_edge *edge = &input->key_edge_states[scancode];
+    struct input_edge *edge = &input->key_edge_states[scancode];
 
     if (edge->is_down)
         return;
@@ -20,12 +20,35 @@ static void key_down(struct input *input, int scancode, u64 current_frame) {
 }
 
 static void key_up(struct input *input, int scancode, u64 current_frame) {
-    struct key_edge *edge = &input->key_edge_states[scancode];
+    struct input_edge *edge = &input->key_edge_states[scancode];
 
     edge->up_frame = current_frame;
     edge->is_down = 0;
 }
 
+static void button_up(struct input *input, SDL_JoyButtonEvent *event, u64 current_frame)
+{
+    if (event->button >= SDL_CONTROLLER_BUTTON_MAX) return;
+    /* printf("button up %d\n", event->button); */
+    struct input_edge *edge = &input->button_edge_states[event->button];
+
+    edge->up_frame = current_frame;
+    edge->is_down = 0;
+}
+
+static void button_down(struct input *input, SDL_JoyButtonEvent *event, u64 current_frame)
+{
+    if (event->button >= SDL_CONTROLLER_BUTTON_MAX) return;
+    /* printf("button down %d\n", event->button); */
+
+    struct input_edge *edge = &input->button_edge_states[event->button];
+
+    if (edge->is_down)
+        return;
+
+    edge->down_frame = current_frame;
+    edge->is_down = 1;
+}
 
 void process_events(struct input *input, u64 current_frame) {
   SDL_Event event;
@@ -47,6 +70,12 @@ void process_events(struct input *input, u64 current_frame) {
     case SDL_KEYUP:
         key_up(input, event.key.keysym.scancode, current_frame);
         break;
+    case SDL_JOYBUTTONUP:
+        button_up(input, &event.jbutton, current_frame);
+        break;
+    case SDL_JOYBUTTONDOWN:
+        button_down(input, &event.jbutton, current_frame);
+        break;
     case SDL_MOUSEBUTTONDOWN:
         if (event.button.button <= MOUSE_BUTTONS)
             input->mbuttons[event.button.button-1] = 1;
@@ -106,13 +135,19 @@ void input_init(struct input *input) {
   assert(input->keystates);
 }
 
-int is_key_down_on_frame(struct input *input, u8 scancode, u64 frame) {
-    struct key_edge *edge = &input->key_edge_states[scancode];
+bool is_key_down_on_frame(struct input *input, u8 scancode, u64 frame) {
+    struct input_edge *edge = &input->key_edge_states[scancode];
 
     // is_down is implied, but do it for good measure
     return edge->down_frame == frame && edge->is_down;
 }
 
+bool is_button_down_on_frame(struct input *input, SDL_GameControllerButton button, u64 frame)
+{
+    struct input_edge *edge = &input->button_edge_states[button];
+    return edge->down_frame == frame && edge->is_down;
+}
+
 
 void input_reset(struct input *input) {
     input->mdx = 0;
diff --git a/src/input.h b/src/input.h
@@ -19,12 +19,7 @@
 #define FLAG_KEY_DOWN (1<<0)
 #define FLAG_KEY_UP   (1<<1)
 
-enum key_edge_state {
-  EDGE_KEY_DOWN = 1 << 0,
-  EDGE_KEY_UP   = 1 << 1,
-};
-
-struct key_edge {
+struct input_edge {
     int is_down;
     u64 down_frame;
     u64 up_frame;
@@ -34,6 +29,7 @@ struct input {
   /* enum key_state keys[0x7F-0x1F]; */
     u8 const *keystates;
     SDL_Keymod modifiers;
+    SDL_GameController *controller;
     int mx, my, last_mx, last_my;
     int mdx, mdy;
     float wheel_x, wheel_y;
@@ -46,12 +42,14 @@ struct input {
     /* u64 up_key_frames[KEY_BUFFER_SIZE]; */
     /* u8 frame_down_keys[KEY_BUFFER_SIZE]; */
     /* u8 frame_up_keys[KEY_BUFFER_SIZE]; */
-    struct key_edge key_edge_states[SDL_NUM_SCANCODES];
+    struct input_edge key_edge_states[SDL_NUM_SCANCODES];
+    struct input_edge button_edge_states[SDL_CONTROLLER_BUTTON_MAX];
 };
 
 int input_is_dragging(struct input *input, int mouse_button);
 
-int is_key_down_on_frame(struct input *input, u8 scancode, u64 frame);
+bool is_key_down_on_frame(struct input *input, u8 scancode, u64 frame);
+bool is_button_down_on_frame(struct input *input, SDL_GameControllerButton button, u64 frame);
 
 void input_init(struct input *input);
 
diff --git a/src/update.c b/src/update.c
@@ -348,12 +348,12 @@ static void camera_keep_above_ground(struct terrain *terrain,
     }
 }
 
-static void entity_jump(struct entity *ent)
+static void entity_jump(struct entity *ent, float amount)
 {
     float dir[3];
     debug("jumping\n");
     vec3_normalize(ent->velocity, dir);
-    vec3_add(dir, V3(0,0,1.0), dir);
+    vec3_add(dir, V3(0, 0, amount), dir);
     vec3_add(ent->velocity, dir, ent->velocity);
 }
 
@@ -409,8 +409,9 @@ static void player_update(struct game *game, struct entity *player)
     }
 
     if (player->flags & ENT_ON_GROUND &&
-        was_key_pressed_this_frame(game, SDL_SCANCODE_SPACE)) {
-        entity_jump(player);
+        (was_key_pressed_this_frame(game, SDL_SCANCODE_SPACE) ||
+         was_button_pressed_this_frame(game, SDL_CONTROLLER_BUTTON_X))) {
+        entity_jump(player, 0.5);
     }
 
     /* debug("player velocity %f %f %f\n", */