commit eb14d3882d3db43f762989e0f8225415b4cdda1c
parent cff1ee0c2406cfd95201db625be7560c69d9038a
Author: William Casarin <jb55@jb55.com>
Date:   Tue, 13 Nov 2018 12:07:06 -0800
input edge states, free camera
Diffstat:
13 files changed, 200 insertions(+), 92 deletions(-)
diff --git a/Makefile b/Makefile
@@ -17,7 +17,6 @@ OBJS += $(SRC)/camera.o
 OBJS += $(SRC)/debug.o
 OBJS += $(SRC)/delaunay.o
 OBJS += $(SRC)/entity.o
-OBJS += $(SRC)/event.o
 OBJS += $(SRC)/fbo.o
 OBJS += $(SRC)/file.o
 OBJS += $(SRC)/game.o
diff --git a/src/entity.h b/src/entity.h
@@ -26,6 +26,7 @@ struct entity_id {
 };
 
 struct entity *init_entity(struct entity *);
+struct entity *delete_entities();
 void init_entity_system();
 struct entity *get_entity(struct entity_id *);
 struct entity *get_all_entities(u32 *count, struct entity_id **ids);
diff --git a/src/event.c b/src/event.c
@@ -4,55 +4,3 @@
 #include "input.h"
 #include "game.h"
 
-void process_events(struct game *game, float *camera) {
-  SDL_Event event;
-  int mdx = 0;
-  int mdy = 0;
-
-  struct input *input = &game->input;
-
-  input->last_mx = game->input.mx;
-  input->last_my = game->input.my;
-
-  input_reset(&game->input);
-
-  while (SDL_PollEvent(&event)) {
-    switch (event.type) {
-    case SDL_MOUSEWHEEL:
-        input->wheel_x = event.wheel.x;
-        input->wheel_y = event.wheel.y;
-        break;
-    case SDL_KEYDOWN:
-    case SDL_KEYUP:
-      handle_key(input, event.key);
-      break;
-    case SDL_MOUSEBUTTONDOWN:
-        if (event.button.button <= MOUSE_BUTTONS)
-            input->mbuttons[event.button.button-1] = 1;
-
-        break;
-    case SDL_MOUSEBUTTONUP:
-        if (event.button.button <= MOUSE_BUTTONS)
-            input->mbuttons[event.button.button-1] = 0;
-        break;
-    case SDL_MOUSEMOTION:
-        input->mx = event.motion.x;
-        input->my = event.motion.y;
-        input->mdx += event.motion.xrel;
-        input->mdy += event.motion.yrel;
-        break;
-    case SDL_WINDOWEVENT:
-      switch (event.window.event) {
-      case SDL_WINDOWEVENT_RESIZED:
-        handle_resize(game, event.window.data1, event.window.data2);
-        break;
-      }
-      break;
-    case SDL_QUIT:
-      SDL_Quit();
-      exit(0);
-    }
-
-  }
-
-}
diff --git a/src/event.h b/src/event.h
@@ -6,6 +6,4 @@
 #include "input.h"
 #include "game.h"
 
-void process_events(struct game *game, float *camera);
-
 #endif /* PA_EVENT_H */
diff --git a/src/game.c b/src/game.c
@@ -20,6 +20,10 @@ mat4 *cam_init = (float[16]){
   -71.766136, -47.881512, -44.216671, 1.000000
 };
 
+int was_key_pressed_this_frame(struct game *game, int scancode) {
+    return is_key_down_on_frame(&game->input, scancode, game->frame);
+}
+
 static void camera_update(struct node *node) {
   mat4 *persp = (float*)node->custom_update_data;
   mat4 *mat = (float*)node->mat;
@@ -34,6 +38,12 @@ struct entity *get_player(struct resources *res) {
     return player;
 }
 
+struct entity *get_terrain_entity(struct terrain *t) {
+    struct entity *ent = get_entity(&t->entity_id);
+    assert(ent);
+    return ent;
+}
+
 static void init_user_settings(struct user_settings *settings) {
     SDL_SetRelativeMouseMode(SDL_TRUE);
     settings->mouse_sens = 0.1;
@@ -48,7 +58,6 @@ void game_init(struct game *game, int width, int height) {
     struct resources *res = &game->test_resources;
     mat4 *mvp = res->test_mvp;
     struct node *root = &res->root;
-    struct node *camera = &res->camera.node;
     struct node *sun_camera = &res->sun_camera;
     struct terrain *terrain = &game->terrain;
     struct entity *player;
@@ -56,6 +65,8 @@ void game_init(struct game *game, int width, int height) {
     mat4 *light_dir = res->light_dir;
     int ok = 0;
 
+    game->frame = 0;
+
     const double size = 10000.0;
 
     terrain->settings = (struct perlin_settings){
@@ -104,22 +115,25 @@ void game_init(struct game *game, int width, int height) {
 
     node_init(root);
     node_init(sun_camera);
-    init_orbit(&res->camera);
+    init_orbit(&res->orbit_camera);
+
 
     // ENTITIES
 
     // player entity
     player = new_entity(&res->player_id);
+    assert(res->player_id.index == 1);
     ok = load_model(&player->model, "pirate-officer");
     assert(ok);
     player->node.label = "player";
     node_attach(&player->node, root);
-    /* node_attach(&res->camera.node, &player->node); */
     node_translate(&player->node, V3(terrain->size/2.,terrain->size/2.,0.0));
 
-    res->camera.coords.azimuth = -quat_yaw(player->node.orientation) - RAD(90.0);
-    res->camera.coords.inclination = RAD(60);
-    res->camera.coords.radius = 5.0;
+    res->orbit_camera.coords.azimuth = -quat_yaw(player->node.orientation) - RAD(90.0);
+    res->orbit_camera.coords.inclination = RAD(60);
+    res->orbit_camera.coords.radius = 5.0;
+
+    res->camera_node = &res->orbit_camera.node;
 
     struct entity *tower = new_entity(NULL);
     ok = load_model(&tower->model, "tower");
@@ -137,10 +151,18 @@ void game_init(struct game *game, int width, int height) {
     // player init
 
     root->label = "root";
-    camera->label = "camera";
 
     input_init(&game->input);
 
+    // free camera
+    node_init(&res->free_camera);
+    res->free_camera.label = "free_camera";
+    node_attach(&res->free_camera, &player->node);
+    quat_axis_angle(V3(1,0,0), -45, res->free_camera.orientation);
+    node_rotate(&res->free_camera, V3(100, 0, 0));
+    node_translate(&res->free_camera, V3(0,-40,20));
+
+
     // FBO STUFF
     init_fbo(&res->shadow_buffer);
     resize_fbos(player, &res->shadow_buffer, res->proj_ortho, width, height);
diff --git a/src/game.h b/src/game.h
@@ -60,7 +60,9 @@ struct resources {
 
 	struct node root;
 	struct entity_id player_id;
-	struct orbit camera;
+	struct orbit orbit_camera;
+	struct node free_camera;
+    const struct node *camera_node;
 	struct node sun_camera;
 
     u32 test_cubemap;
@@ -84,6 +86,7 @@ struct game {
     int counter;
     int seed;
     float dt;
+    u64 frame;
     struct user_settings user_settings;
     struct ui ui;
     struct resources test_resources;
@@ -92,7 +95,10 @@ struct game {
 };
 
 struct entity *get_player(struct resources *);
+struct entity *get_terrain_entity(struct terrain *);
 void game_init(struct game *game, int width, int height);
 void should_update(struct game *game);
+int was_key_pressed_this_frame(struct game *game, int scancode);
+int is_free_camera(struct game *game);
 
 #endif /* PA_GAME_H */
diff --git a/src/input.c b/src/input.c
@@ -3,9 +3,95 @@
 #include "util.h"
 #include "common.h"
 
+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];
+
+    if (edge->is_down)
+        return;
+
+    edge->down_frame = current_frame;
+    edge->is_down = 1;
+
+    // might be useful to know when it was last up
+    /* edge->up_frame = 0; */
+}
+
+static void key_up(struct input *input, int scancode, u64 current_frame) {
+    struct key_edge *edge = &input->key_edge_states[scancode];
+
+    edge->up_frame = current_frame;
+    edge->is_down = 0;
+}
+
+
+void process_events(struct input *input, u64 current_frame) {
+  SDL_Event event;
+
+  input->last_mx = input->mx;
+  input->last_my = input->my;
+
+  input_reset(input);
+
+  while (SDL_PollEvent(&event)) {
+    switch (event.type) {
+    case SDL_MOUSEWHEEL:
+        input->wheel_x = event.wheel.x;
+        input->wheel_y = event.wheel.y;
+        break;
+    case SDL_KEYDOWN:
+        key_down(input, event.key.keysym.scancode, current_frame);
+        break;
+    case SDL_KEYUP:
+        key_up(input, event.key.keysym.scancode, current_frame);
+        break;
+    case SDL_MOUSEBUTTONDOWN:
+        if (event.button.button <= MOUSE_BUTTONS)
+            input->mbuttons[event.button.button-1] = 1;
+
+        break;
+    case SDL_MOUSEBUTTONUP:
+        if (event.button.button <= MOUSE_BUTTONS)
+            input->mbuttons[event.button.button-1] = 0;
+        break;
+    case SDL_MOUSEMOTION:
+        input->mx = event.motion.x;
+        input->my = event.motion.y;
+        input->mdx += event.motion.xrel;
+        input->mdy += event.motion.yrel;
+        break;
+    case SDL_WINDOWEVENT:
+      switch (event.window.event) {
+      case SDL_WINDOWEVENT_RESIZED:
+          if (!event.window.data1)
+              continue;
+          printf("resizing %d %d\n", event.window.data1, event.window.data2);
+          input->resized_width = event.window.data1;
+          input->resized_height = event.window.data2;
+          assert(input->resized_width);
+          assert(input->resized_height);
+        break;
+      }
+      break;
+    case SDL_QUIT:
+      SDL_Quit();
+      exit(0);
+    }
+
+  }
+
+  if (input->resized_width)
+    printf("checking resize %d %d\n", input->resized_width,
+            input->resized_height);
+
+}
+
 void input_init(struct input *input) {
   /* memset(input->keys, 0, sizeof(input->keys[0]) * ARRAY_SIZE(input->keys)); */
   input->keystates = SDL_GetKeyboardState(NULL);
+  assert(sizeof(input->key_edge_states) == SDL_NUM_SCANCODES * sizeof(input->key_edge_states[0]));
+  memset(input->key_edge_states, 0, sizeof(input->key_edge_states));
   input->mx = 0;
   input->my = 0;
   input->mdx = 0;
@@ -14,11 +100,16 @@ void input_init(struct input *input) {
   input->wheel_y = 0;
   input->last_mx = 0;
   input->last_my = 0;
+  input->resized_height = 0;
+  input->resized_width = 0;
   assert(input->keystates);
 }
 
-void handle_key(struct input *input, SDL_KeyboardEvent key) {
-  input->modifiers = SDL_GetModState();
+int is_key_down_on_frame(struct input *input, u8 scancode, u64 frame) {
+    struct key_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;
 }
 
 
@@ -27,6 +118,8 @@ void input_reset(struct input *input) {
     input->mdy = 0;
     input->wheel_x = 0;
     input->wheel_y = 0;
+    input->resized_height = 0;
+    input->resized_width = 0;
 }
 
 int input_is_dragging(struct input *input, int mouse_button) {
diff --git a/src/input.h b/src/input.h
@@ -14,6 +14,22 @@
 
 #define MOUSE_BUTTONS 5
 
+/* #define KEY_BUFFER_SIZE 32 */
+
+#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 {
+    int is_down;
+    u64 down_frame;
+    u64 up_frame;
+};
+
 struct input {
   /* enum key_state keys[0x7F-0x1F]; */
     u8 const *keystates;
@@ -22,14 +38,27 @@ struct input {
     int mdx, mdy;
     float wheel_x, wheel_y;
     int mbuttons[MOUSE_BUTTONS];
+    int n_frame_down_keys;
+    int n_frame_up_keys;
+    int resized_width;
+    int resized_height;
+    /* u64 down_key_frames[KEY_BUFFER_SIZE]; */
+    /* 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];
 };
 
 int input_is_dragging(struct input *input, int mouse_button);
 
+int is_key_down_on_frame(struct input *input, u8 scancode, u64 frame);
+
 void input_init(struct input *input);
 
 void input_reset(struct input *input);
 
 void handle_key(struct input *input, SDL_KeyboardEvent);
 
+void process_events(struct input *input, u64 current_frame);
+
 #endif /* POLYADVENT_INPUT_H */
diff --git a/src/main.c b/src/main.c
@@ -73,13 +73,20 @@ int main(void)
     struct render_config default_config = {
       .draw_ui = 0,
       .is_depth_pass = 0,
-      .camera = game.test_resources.camera.node.mat,
+      .camera = game.test_resources.camera_node->mat,
       .projection = game.test_resources.proj_persp,
       .depth_vp = depth_vp
     };
 
     while (1) {
-        process_events(&game, game.test_resources.proj_persp);
+        game.frame++;
+        process_events(&game.input, game.frame);
+        if (game.input.resized_height) {
+            printf("handling resize %d %d\n", game.input.resized_width,
+                   game.input.resized_height);
+            handle_resize(&game, game.input.resized_width, game.input.resized_height);
+        }
+        default_config.camera = game.test_resources.camera_node->mat;
         double new_time = hires_time_in_seconds();
         double frame_time = new_time - last;
         game.dt = frame_time;
diff --git a/src/orbit.c b/src/orbit.c
@@ -73,6 +73,7 @@ static void orbit_node_update(struct node *node) {
 
 void init_orbit(struct orbit *orbit) {
     node_init(&orbit->node);
+    orbit->node.label = "orbit_camera";
     /* orbit->node.custom_update = orbit_node_update; */
     /* orbit->node.custom_update_data = orbit; */
 }
diff --git a/src/render.c b/src/render.c
@@ -260,7 +260,7 @@ void render (struct game *game, struct render_config *config) {
     mat4 *projection = config->projection;
     mat4 *light = res->light_dir;
 
-    float *camera = config->camera;
+    const mat4 *camera = config->camera;
     u32 num_entities;
 
     struct entity *entities =
@@ -276,7 +276,7 @@ void render (struct game *game, struct render_config *config) {
 
     /* mat4_multiply(view_proj, res->skybox.node.mat, mvp); */
 
-    mat4_inverse(camera, view);
+    mat4_inverse((float*)camera, view);
     mat4_multiply(projection, view, view_proj);
 
     if (config->is_depth_pass) {
@@ -287,7 +287,7 @@ void render (struct game *game, struct render_config *config) {
         glCullFace(GL_BACK);
     }
 
-    mat4_inverse(camera, view);
+    mat4_inverse((float *)camera, view);
     mat4_multiply(projection, view, view_proj);
 
     glBindTexture(GL_TEXTURE_CUBE_MAP, res->skybox.model.texture);
@@ -351,7 +351,7 @@ void render (struct game *game, struct render_config *config) {
     }
 
     if (!config->is_depth_pass) {
-        mat4_inverse(camera, view);
+        mat4_inverse((float*)camera, view);
         mat4_remove_translations(view);
         mat4_multiply(projection, view, view_proj);
 
diff --git a/src/render.h b/src/render.h
@@ -8,7 +8,7 @@ struct game;
 struct render_config {
     int draw_ui;
     int is_depth_pass;
-    float *camera;
+    const float *camera;
     float *projection;
     float *depth_vp;
 };
diff --git a/src/update.c b/src/update.c
@@ -8,6 +8,7 @@
 #include "camera.h"
 #include "poisson.h"
 #include "uniform.h"
+#include "game.h"
 #include "mat_util.h"
 #include "shader.h"
 #include "file.h"
@@ -55,7 +56,7 @@ static void movement(struct game *game, struct node *node, float speed_mult) {
     /* if (game->input.keystates[SDL_SCANCODE_DOWN]) */
     /*   node_translate(node, V3(0, 0, -amt)); */
 
-    if (game->input.keystates[SDL_SCANCODE_P]) {
+    if (was_key_pressed_this_frame(game, SDL_SCANCODE_P)) {
         printf("%f %f %f\n",
                 node->pos[0],
                 node->pos[1],
@@ -312,15 +313,14 @@ void orbit_update_from_mouse(struct orbit *camera, struct input *input,
 
 }
 
-static void orbit_keep_above_ground(struct game *game) {
-    struct resources *res = &game->test_resources;
-
-    if (!(get_entity(&game->terrain.entity_id)->flags & ENT_INVISIBLE)) {
-        float *camera_world = node_world(&res->camera.node);
+static void camera_keep_above_ground(struct terrain *terrain,
+                                     const struct node *camera) {
+    if (!(get_entity(&terrain->entity_id)->flags & ENT_INVISIBLE)) {
+        float *camera_world = node_world((struct node*)camera);
         /* float *target = node_world(&get_player(res)->node); */
         /* spherical_pos(&res->camera.coords, target, camera_world); */
         float cam_terrain_z =
-            game->terrain.fn(&game->terrain, camera_world[0], camera_world[1]);
+            terrain->fn(terrain, camera_world[0], camera_world[1]);
 
         const float bias = 2.0;
 
@@ -331,18 +331,17 @@ static void orbit_keep_above_ground(struct game *game) {
 
 static void player_update(struct game *game, struct entity *player) {
 
-    struct orbit *camera = &game->test_resources.camera;
+    struct resources *res = &game->test_resources;
+    struct orbit *camera = &res->orbit_camera;
+
     orbit_update_from_mouse(camera, &game->input, game->user_settings.mouse_sens,
                             player, game->dt);
 
-    orbit_keep_above_ground(game);
-
-    /* look_at(node_world(&camera->node), node_world(&player->node), UP_VEC, */
-    /*         camera->node.mat); */
+    camera_keep_above_ground(&game->terrain, res->camera_node);
 
     // move player camera toward camera orientation
     if (input_is_dragging(&game->input, SDL_BUTTON_RIGHT)) {
-        float yaw = game->test_resources.camera.coords.azimuth;
+        float yaw = game->test_resources.orbit_camera.coords.azimuth;
         quat_axis_angle(V3(0.0, 0.0, 1.0), -yaw - RAD(90), player->node.orientation);
     }
     player_terrain_collision(&game->terrain, player);
@@ -372,25 +371,30 @@ void update (struct game *game) {
     /* vec3_scale(camera_dir, -1, camera_dir); */
 
 	if (game->input.modifiers & KMOD_LALT) {
-		movement(game, &res->camera.node, 1.0);
+        if (res->camera_node == &res->free_camera)
+            movement(game, &res->free_camera, 1.0);
 	}
 	else {
 		player_movement(game, player);
 	}
     player_update(game, player);
 
-
-#ifdef DEBUG
-	if (game->input.keystates[SDL_SCANCODE_R])
+	if (was_key_pressed_this_frame(game, SDL_SCANCODE_R))
 		try_reload_shaders(res);
-#endif
 
-	if (game->input.keystates[SDL_SCANCODE_C])
+	if (was_key_pressed_this_frame(game, SDL_SCANCODE_C))
 		printf("light_dir %f %f %f\n", light[0], light[1], light[2]);
 
-	if (game->input.keystates[SDL_SCANCODE_F])
+	if (was_key_pressed_this_frame(game, SDL_SCANCODE_F))
 		toggle_fog = 1;
 
+	if (was_key_pressed_this_frame(game, SDL_SCANCODE_EQUALS)) {
+        if (res->camera_node != &res->free_camera)
+            res->camera_node = &res->free_camera;
+        else
+            res->camera_node = &res->orbit_camera.node;
+    }
+
 	if (toggle_fog) {
 		res->fog_on = !res->fog_on;
 		toggle_fog = 0;