polyadvent

A game engine from scratch in C
git clone git://jb55.com/polyadvent
Log | Files | Refs | README

commit 9456beab576d8a918ec9efb15ece6a7be32bb158
parent fbd0007a1e3cede28d71dd1939595a44632caf6d
Author: William Casarin <jb55@jb55.com>
Date:   Tue,  6 Nov 2018 18:20:26 -0800

spherical coord camera

Diffstat:
Msrc/event.c | 15+++++++--------
Msrc/game.c | 25+++++++++++++++----------
Msrc/game.h | 8++++++--
Msrc/input.c | 12+++++-------
Msrc/input.h | 2+-
Msrc/main.c | 2+-
Msrc/mat_util.c | 14++++++++++----
Msrc/mat_util.h | 2+-
Msrc/node.c | 18+++++++++++-------
Msrc/node.h | 5+++++
Msrc/orbit.c | 39++++++++++++++++++++++++++++++++-------
Msrc/orbit.h | 29++++++++++++++---------------
Msrc/quat.c | 5+++++
Msrc/quat.h | 1+
Msrc/update.c | 40+++++++++++++++++++++++++++++++++-------
Msrc/util.h | 1+
16 files changed, 148 insertions(+), 70 deletions(-)

diff --git a/src/event.c b/src/event.c @@ -9,6 +9,9 @@ void process_events(struct game *game, float *camera) { int mdx = 0; int mdy = 0; + game->input.last_mx = game->input.mx; + game->input.last_my = game->input.my; + input_reset(&game->input); while (SDL_PollEvent(&event)) { @@ -27,14 +30,10 @@ void process_events(struct game *game, float *camera) { game->input.mbuttons[event.button.button-1] = 0; break; case SDL_MOUSEMOTION: - if (event.button.button) { - /* printf("drag... %d %d\n", event.motion.xrel, event.motion.yrel); */ - game->input.last_mx = game->input.mx; - game->input.last_my = game->input.mx; - game->input.mx = event.motion.x; - game->input.my = event.motion.y; - - } + game->input.mx = event.motion.x; + game->input.my = event.motion.y; + game->input.mdx += event.motion.xrel; + game->input.mdy += event.motion.yrel; break; case SDL_WINDOWEVENT: switch (event.window.event) { diff --git a/src/game.c b/src/game.c @@ -31,16 +31,21 @@ struct entity *get_player(struct resources *res) { return player; } +static void init_user_settings(struct user_settings *settings) { + SDL_SetRelativeMouseMode(SDL_TRUE); + settings->mouse_sens = 0.2; +} + void game_init(struct game *game, int width, int height) { init_gl(&game->test_resources, width, height); init_entity_system(); + init_user_settings(&game->user_settings); check_gl(); - float pos[3]; struct resources *res = &game->test_resources; mat4 *mvp = res->test_mvp; struct node *root = &res->root; - struct node *camera = &res->camera; + struct node *camera = &res->camera.node; struct node *sun_camera = &res->sun_camera; struct terrain *terrain = &game->terrain; struct entity *player; @@ -88,10 +93,6 @@ void game_init(struct game *game, int width, int height) { game->test_resources.fog_on = 1; game->test_resources.diffuse_on = 0; - res->orbit_camera.azimuth = RAD(90.0); - res->orbit_camera.inclination = RAD(180.0); - res->orbit_camera.radius = RAD(180.0); - node_init(root); node_init(camera); node_init(sun_camera); @@ -106,6 +107,10 @@ void game_init(struct game *game, int width, int height) { node_attach(&player->node, root); 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 = 200.0; + struct entity *tower = new_entity(NULL); ok = load_model(&tower->model, "tower"); assert(ok); @@ -122,12 +127,12 @@ void game_init(struct game *game, int width, int height) { root->label = "root"; camera->label = "camera"; - node_attach(camera, &player->node); + /* node_attach(camera, &player->node); */ - quat_axis_angle(V3(1,0,0), -45, camera->orientation); + /* quat_axis_angle(V3(1,0,0), -45, camera->orientation); */ - node_rotate(camera, V3(100, 0, 0)); - node_translate(camera, V3(0,-40,20)); + /* node_rotate(camera, V3(100, 0, 0)); */ + /* node_translate(camera, V3(0,-40,20)); */ input_init(&game->input); diff --git a/src/game.h b/src/game.h @@ -57,8 +57,7 @@ struct resources { struct node root; struct entity_id player_id; - struct orbit orbit_camera; - struct node camera; + struct orbit camera; struct node sun_camera; float time; @@ -72,10 +71,15 @@ struct resources { float proj_ortho[MAT4_ELEMS]; }; +struct user_settings { + float mouse_sens; +}; + struct game { int counter; int seed; float dt; + struct user_settings user_settings; struct ui ui; struct resources test_resources; struct input input; diff --git a/src/input.c b/src/input.c @@ -6,9 +6,10 @@ void input_init(struct input *input) { /* memset(input->keys, 0, sizeof(input->keys[0]) * ARRAY_SIZE(input->keys)); */ input->keystates = SDL_GetKeyboardState(NULL); - input->is_dragging = 0; input->mx = 0; input->my = 0; + input->mdx = 0; + input->mdy = 0; input->last_mx = 0; input->last_my = 0; assert(input->keystates); @@ -20,13 +21,10 @@ void handle_key(struct input *input, SDL_KeyboardEvent key) { void input_reset(struct input *input) { - input->is_dragging = 0; - - for (int i = 0; i < MOUSE_BUTTONS; ++i) - input->mbuttons[i] = 0; + input->mdx = 0; + input->mdy = 0; } int input_is_dragging(struct input *input, int mouse_button) { - return input->mbuttons[mouse_button-1] && - (input->last_mx != input->mx || input->last_my != input->my); + return input->mbuttons[mouse_button-1]; } diff --git a/src/input.h b/src/input.h @@ -19,7 +19,7 @@ struct input { u8 const *keystates; SDL_Keymod modifiers; int mx, my, last_mx, last_my; - int is_dragging; + int mdx, mdy; int mbuttons[MOUSE_BUTTONS]; }; diff --git a/src/main.c b/src/main.c @@ -73,7 +73,7 @@ int main(void) struct render_config default_config = { .draw_ui = 1, .is_depth_pass = 0, - .camera = game.test_resources.camera.mat, + .camera = game.test_resources.camera.node.mat, .projection = game.test_resources.proj_persp, .depth_vp = depth_vp }; diff --git a/src/mat_util.c b/src/mat_util.c @@ -1,10 +1,7 @@ #include "mat_util.h" -mat4 *mat4_create_transform(float *pos, float *scale, quat *orientation, mat4 *dest) { - float rot[9]; - quat_to_mat3(orientation, rot); - +mat4 *mat4_create_transform(float *pos, float *scale, float *rot, mat4 *dest) { dest[0] = scale[0] * rot[0]; dest[1] = scale[0] * rot[1]; dest[2] = scale[0] * rot[2]; @@ -28,3 +25,12 @@ mat4 *mat4_create_transform(float *pos, float *scale, quat *orientation, mat4 *d return dest; } + +vec3 *vec3_forward(vec3 *v, quat *orientation, float *dir, float *dest) { + float q[4] = {0}; + float movement[3] = {0}; + quat_inverse(orientation, q); + quat_multiply_vec3(q, dir, movement); + vec3_add(v, movement, dest); + return dest; +} diff --git a/src/mat_util.h b/src/mat_util.h @@ -8,6 +8,6 @@ void look_at(vec3 *eye, vec3 *target, vec3 *up, mat4 *dest); mat4 *mat4_create_transform(float *pos, float *scale, quat *orientation, mat4 *dest); -vec3 *vec3_forward(vec3 *p, quat orientation, vec3 *dest); +vec3 *vec3_forward(vec3 *p, quat *orientation, vec3 *dir, float *dest); #endif /* POLYADVENT_MAT_UTIL_H */ diff --git a/src/node.c b/src/node.c @@ -2,6 +2,7 @@ #include "node.h" #include "mat_util.h" +#include <string.h> #include <stdio.h> #include <assert.h> @@ -14,6 +15,7 @@ struct node *node_init(struct node *node) { node->n_children = 0; for (int i = 0; i < MAX_NODE_CHILDREN; ++i) node->children[i] = NULL; + node->flags = 0; node->parent = NULL; node->label = "unknown"; node->needs_recalc = 0; @@ -52,7 +54,8 @@ void node_rotate(struct node *node, vec3 *axis_angles) { node_mark_for_recalc(node); } -int node_needs_recalc(struct node *node) { +int node_needs_recalc(struct node *node) +{ return (node->parent && node->parent->needs_recalc) || node->needs_recalc; } @@ -81,6 +84,7 @@ static void node_recalc_children(struct node *node) { int node_recalc(struct node *node) { assert(node); + float rot[9] = {1.0}; if (node->parent && node_needs_recalc(node->parent)) node_recalc(node->parent); @@ -92,7 +96,8 @@ int node_recalc(struct node *node) { node->needs_recalc = 0; - mat4_create_transform(node->pos, node->scale, node->orientation, node->mat); + quat_to_mat3(node->orientation, rot); + mat4_create_transform(node->pos, node->scale, rot, node->mat); if (node->parent) { assert(!node->parent->needs_recalc); @@ -116,11 +121,10 @@ void node_attach(struct node *node, struct node *to) { } void node_forward(struct node *node, float *dir) { - float movement[3] = {0}; - float q[4] = {0}; - quat_inverse(node->orientation, q); - quat_multiply_vec3(q, dir, movement); - vec3_add(node->pos, movement, node->pos); + vec3_forward(node->pos, node->orientation, dir, node->pos); + /* quat_inverse(node->orientation, q); */ + /* quat_multiply_vec3(q, dir, movement); */ + /* vec3_add(node->pos, movement, node->pos); */ /* printf("dir %f %f %f\nmovement %f %f %f\nquat %f %f %f %f\n", */ /* dir[0], dir[1], dir[2], */ /* movement[0], movement[1], movement[2], */ diff --git a/src/node.h b/src/node.h @@ -4,6 +4,10 @@ #define MAX_NODE_CHILDREN 4 +enum node_flags { + NODE_IGNORE_RECALC = 1 << 0 +}; + struct node { float pos[3]; float rot[3]; @@ -12,6 +16,7 @@ struct node { float orientation[4]; char *label; int needs_recalc; + int flags; int n_children; void (*custom_update)(struct node*); void *custom_update_data; diff --git a/src/orbit.c b/src/orbit.c @@ -2,20 +2,45 @@ #include "orbit.h" #include "node.h" #include "vec3.h" +#include "mat4.h" #include "quat.h" +#include "util.h" #include <math.h> -void orbit_to_mat4(struct orbit *orbit, float *m) +float *spherical_to_cartesian(struct spherical *s, float *v3) { - quat_axis_angle(orbit->angles.ypr) + float theta = s->inclination; + float phi = s->azimuth; + + float sin_theta = sin(theta); + float cos_phi = cos(phi); + float cos_theta = cos(theta); + + // to cartesian + v3[0] = s->radius * sin_theta * cos_phi; + v3[1] = s->radius * sin_theta * sin(phi); + v3[2] = s->radius * cos_theta; + + return v3; } -/* static void orbit_update_node(struct node *node) { */ -/* } */ -void orbit_to_node(struct orbit *orbit, struct node *node) { - /* orbit_to_quat(orbit, node->orientation); */ - node_mark_for_recalc(node); +// from: in +// to: out +float *spherical_pos(struct spherical *s, vec3 *from, vec3 *to) { + float spherical_offset[3]; + spherical_to_cartesian(s, spherical_offset); + vec3_add(from, spherical_offset, to); + return to; } +float *spherical_look_at(struct spherical *s, vec3 *target, mat4 *mat) { + float eye[3]; + + spherical_pos(s, target, eye); + look_at(eye, target, V3(0.0, 0.0, 1.0), mat); + return mat; +} + + diff --git a/src/orbit.h b/src/orbit.h @@ -2,24 +2,23 @@ #ifndef ORBIT_H #define ORBIT_H -struct node; +#include "vec3.h" +#include "node.h" +#include "mat4.h" + +struct spherical { + float radius; + float inclination; + float azimuth; +}; struct orbit { - float dist; - union { - struct { - float yaw; - float pitch; - float roll; - }; - - float ypr[3]; - } angles; + struct spherical coords; + struct node node; }; - -void orbit_to_node(struct orbit *orbit, struct node *node); -void orbit_to_quat(struct orbit *, float *a); - +float *spherical_pos(struct spherical *s, vec3 *from, vec3 *to); +float *spherical_look_at(struct spherical *s, vec3 *target, mat4 *mat); +float *spherical_to_cartesian(struct spherical *s, float *v3); #endif /* ORBIT_H */ diff --git a/src/quat.c b/src/quat.c @@ -74,6 +74,11 @@ void quat_to_mat3(quat *quat, float *dest) { dest[8] = 1.0 - (xx + yy); } + +float quat_yaw(quat *q) { + return atan2(q[2],q[3])*2.0; +} + void quat_multiply_vec3(quat *quat, float *vec, float *dest) { float x = vec[0], y = vec[1], z = vec[2]; float qx = quat[0], qy = quat[1], qz = quat[2], qw = quat[3]; diff --git a/src/quat.h b/src/quat.h @@ -11,6 +11,7 @@ void quat_multiply(quat *a, quat *b, quat *dest); void quat_axis_angle(float *axis, float angle, quat *dest); void quat_from_axes(float yaw, float pitch, float roll); void quat_to_mat3(quat *quat, float *dest); +float quat_yaw(quat *quat); void quat_multiply_vec3(quat *quat, float *vec, float *dest); quat *quat_inverse(quat *q, quat *dest); diff --git a/src/update.c b/src/update.c @@ -8,6 +8,7 @@ #include "camera.h" #include "poisson.h" #include "uniform.h" +#include "mat_util.h" #include "shader.h" #include "file.h" #include <math.h> @@ -299,17 +300,42 @@ static void gravity(struct game *game) { node_translate(&player->node, V3(0.0, 0.0, -1.0)); } -static void player_update(struct game *game, struct entity *player) { - struct orbit *orbit_camera = &game->test_resources.orbit_camera; - /* orbit_camera->radius += game->dt * 4.0; */ - /* orbit_camera->inclination += game->dt * 2.0; */ - /* orbit_camera->azimuth += game->dt * 2.0; */ - /* orbit_to_node(orbit_camera, &game->test_resources.camera); */ +void orbit_update_from_mouse(struct orbit *camera, struct input *input, + float mouse_sens, struct entity *player, + float dt) { + float *target; + struct node *target_node = &player->node; + + node_recalc(target_node); + target = node_world(target_node); + + float mx = 0.0, my = 0.0; + if (input_is_dragging(input, SDL_BUTTON_LEFT) || + input_is_dragging(input, SDL_BUTTON_RIGHT)) { + mx = -input->mdx * mouse_sens * dt; + my = -input->mdy * mouse_sens * dt; + } + + camera->coords.azimuth += mx; + camera->coords.inclination += my; + spherical_look_at(&camera->coords, target, camera->node.mat); +} +static void player_update(struct game *game, struct entity *player) { + orbit_update_from_mouse(&game->test_resources.camera, &game->input, + game->user_settings.mouse_sens, player, game->dt); + // move player camera toward camera orientation + if (input_is_dragging(&game->input, SDL_BUTTON_RIGHT)) { + float yaw = game->test_resources.camera.coords.azimuth; + quat_axis_angle(V3(0.0, 0.0, 1.0), -yaw - RAD(90), player->node.orientation); + node_recalc(&player->node); + } player_terrain_collision(&game->terrain, player); } + + void update (struct game *game) { static int toggle_fog = 0; static int first = 1; @@ -331,7 +357,7 @@ void update (struct game *game) { player_update(game, player); if (game->input.modifiers & KMOD_LALT) { - movement(game, &res->camera, 1.0); + movement(game, &res->camera.node, 1.0); } else if (game->input.modifiers & KMOD_RCTRL) { movement(game, tnode, 5.0); diff --git a/src/util.h b/src/util.h @@ -16,6 +16,7 @@ } \ } +#define UP_VEC V3(0.0, 0.0, 1.0) #define PI 3.14159265 #define TAU 6.2831853