polyadvent

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

commit 7ceffcce1cee3906f774dab6ba64d82a68822b55
parent d4a6203a98bf458167b3b37454f0cd0dc7b6db29
Author: William Casarin <jb55@jb55.com>
Date:   Tue,  1 May 2018 11:55:48 -0700

quats working. finally fixed camera node issues

Diffstat:
Msrc/camera.c | 6+++---
Msrc/game.c | 27+++++++++++++++++----------
Msrc/game.h | 1-
Msrc/main.c | 2+-
Msrc/mat_util.c | 1+
Msrc/mat_util.h | 1+
Msrc/node.c | 91+++++++++++++++++++++++++++++++++++++-------------------------------------------
Msrc/node.h | 7++++---
Msrc/quat.c | 36+++++++++++++++++++++++++++++++++---
Msrc/quat.h | 3+++
Msrc/render.c | 12+++---------
Msrc/update.c | 40+++++++++++++++++++++-------------------
12 files changed, 129 insertions(+), 98 deletions(-)

diff --git a/src/camera.c b/src/camera.c @@ -10,9 +10,9 @@ struct camera *camera_init(struct camera *cam) { void camera_follow(vec3 *cam_pos, vec3 *target, mat4 *cam) { - cam_pos[0] = target[0] - 10; - cam_pos[1] = target[1] - 20; - cam_pos[2] = target[2] + 15; + /* cam_pos[0] = target[0] - 10; */ + /* cam_pos[1] = target[1] - 20; */ + /* cam_pos[2] = target[2] + 15; */ /* printf("cam %f %f %f looking at player %f %f %f\n", */ /* cam_pos[0], cam_pos[1], cam_pos[2], */ /* target[0], target[1], target[2]); */ diff --git a/src/game.c b/src/game.c @@ -9,12 +9,19 @@ mat4 *cam_init = (float[16]){ -71.766136, -47.881512, -44.216671, 1.000000 }; +static void camera_update(struct node *node) { + mat4 *persp = (float*)node->custom_update_data; + mat4 *mat = (float*)node->mat; + + mat4_inverse(mat, mat); + mat4_multiply(persp, mat, mat); +} + void game_init(struct game *game) { mat4 *mvp = game->test_resources.test_mvp; struct node *root = &game->test_resources.root; struct node *camera = &game->test_resources.camera; struct node *player = &game->test_resources.player; - struct node *player_camera = &game->test_resources.player_camera; struct node *terrain_node = &game->test_resources.terrain_node; mat4 *light_dir = game->test_resources.light_dir; @@ -27,30 +34,30 @@ void game_init(struct game *game) { node_init(root); node_init(player); node_init(camera); - node_init(player_camera); node_init(terrain_node); root->label = "root"; player->label = "player"; camera->label = "camera"; - player_camera->label = "player_camera"; terrain_node->label = "terrain_node"; node_attach(player, root); - node_attach(player_camera, player); - node_attach(camera, root); + node_attach(camera, player); + + quat_axis_angle(V3(1,0,0), -45, camera->orientation); + + /* camera->custom_update = camera_update; */ + /* camera->custom_update_data = (void*)game->test_resources.camera_persp; */ /* vec3_all(camera->scale, -1); */ - camera->mirrored = 1; + /* camera->mirrored = 1; */ - node_translate(player, V3(10,10,0)); - node_translate(camera, V3(0,0,20)); - node_translate(player_camera, V3(10,10,20)); + node_translate(player, V3(20,20,0)); + node_translate(camera, V3(0,-30,20)); /* node_recalc(camera); */ /* player_camera->mirrored = 1; */ /* camera->parent = player_camera; */ - quat_axis_angle(V3(1,0,0), 45, camera->orientation); // move the camera a bit /* mat4_translate(camera, 1.0f, 1.0f, 20.0f, camera); */ diff --git a/src/game.h b/src/game.h @@ -32,7 +32,6 @@ struct resources { struct node root; struct node player; - struct node player_camera; struct node camera; struct node terrain_node; diff --git a/src/main.c b/src/main.c @@ -45,7 +45,7 @@ int main(void) game_init(&game); game.terrain = &terrain; - const double size = 2000; + const double size = 1000; const double pdist = 1.7; const double scale = 0.01; /* printf("samples seed %d\n", seed); */ diff --git a/src/mat_util.c b/src/mat_util.c @@ -27,3 +27,4 @@ mat4 *mat4_create_transform(float *pos, float *scale, quat *orientation, mat4 *d return dest; } + diff --git a/src/mat_util.h b/src/mat_util.h @@ -8,5 +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); #endif /* POLYADVENT_MAT_UTIL_H */ diff --git a/src/node.c b/src/node.c @@ -10,13 +10,14 @@ struct node *node_init(struct node *node) { vec3_all(node->pos, 0); vec3_all(node->rot, 0); vec3_all(node->scale, 1.0); + quat_id(node->orientation); node->n_children = 0; for (int i = 0; i < MAX_NODE_CHILDREN; ++i) node->children[i] = NULL; node->parent = NULL; - node->mirrored = 0; node->label = "unknown"; node->needs_recalc = 0; + node->custom_update = 0; node_mark_for_recalc(node); return node; @@ -31,12 +32,19 @@ void node_translate(struct node *node, vec3 *p) { node_mark_for_recalc(node); } -void node_rotate(struct node *node, vec3 *p) { - if (vec3_isall(p, 0)) +void node_rotate(struct node *node, vec3 *axis_angles) { + if (vec3_isall(axis_angles, 0)) return; + for (int i = 0; i < 3; ++i) { + float axis[3] = {0}; + float quat[4]; + axis[i] = 1; + quat_axis_angle(axis, axis_angles[i], quat); + quat_multiply(node->orientation, quat, node->orientation); + } + /* printf("translating %f %f %f\n", p[0], p[1], p[2]); */ - vec3_add(node->rot, p, node->rot); node_mark_for_recalc(node); } @@ -44,6 +52,11 @@ int node_needs_recalc(struct node *node) { return (node->parent && node->parent->needs_recalc) || node->needs_recalc; } +vec3 *node_world(struct node *node) { + assert(!node_needs_recalc(node)); + return &node->mat[M_X]; +} + void node_mark_for_recalc(struct node *node) { static int j = 0; @@ -52,10 +65,8 @@ void node_mark_for_recalc(struct node *node) { node->needs_recalc = 1; - for (int i = 0; i < node->n_children; ++i) { - printf("%d %s marking child %s for recalc\n", j++, node->label, node->children[i]->label); + for (int i = 0; i < node->n_children; ++i) node_mark_for_recalc(node->children[i]); - } } static void node_recalc_children(struct node *node) { @@ -65,60 +76,28 @@ static void node_recalc_children(struct node *node) { } int node_recalc(struct node *node) { - float rotate_axis[3]; - float tmp[16]; - assert(node); + if (node->parent && node_needs_recalc(node->parent)) + node_recalc(node->parent); + if (!node_needs_recalc(node)) { - // XXX: do I need this? - goto recalc_children; + node_recalc_children(node); + return 0; } - printf("recalculating %s\n", node->label); - node->needs_recalc = 0; - if (node->mirrored) { - mat4_create_transform(V3(-node->pos[0], -node->pos[1], -node->pos[2]), - node->scale, node->orientation, node->mat); - } - else - mat4_create_transform(node->pos, node->scale, node->orientation, node->mat); - - /* float m = node->mirrored ? -1 : 1; */ - - /* // FIXME: this seems bad? */ - /* for (int i = 0; i < 3; ++i) { */ - /* if (node->rot[i] != 0) { */ - /* rotate_axis[0] = 0; */ - /* rotate_axis[1] = 0; */ - /* rotate_axis[2] = 0; */ - /* rotate_axis[i] = 1; */ - /* float x = node->pos[0]; */ - /* float y = node->pos[1]; */ - /* float z = node->pos[2]; */ - /* if (!node->mirrored) */ - /* mat4_translate(node->mat, V3(x, y, z), node->mat); */ - /* mat4_rotate(node->mat, node->rot[i]*m, rotate_axis, node->mat); */ - /* if (!node->mirrored) */ - /* mat4_translate(node->mat, V3(-x, -y, -z), node->mat); */ - /* } */ - /* } */ - - /* if (node->pos[0] || node->pos[1] || node->pos[2]) */ - /* mat4_translate(node->mat, V3(node->pos[0]*m,node->pos[1]*m,node->pos[2]*m), */ - /* node->mat); */ - - /* if (node->pos[0] || node->pos[1] || node->pos[2]) */ - /* mat4_translate(node->mat, node->pos, node->mat); */ + mat4_create_transform(node->pos, node->scale, node->orientation, node->mat); if (node->parent) { assert(!node->parent->needs_recalc); - mat4_multiply(node->mat, node->parent->mat, node->mat); + mat4_multiply(node->parent->mat, node->mat, node->mat); } -recalc_children: + if (node->custom_update) + node->custom_update(node); + node_recalc_children(node); return 1; @@ -131,3 +110,17 @@ void node_attach(struct node *node, struct node *to) { node->parent = to; to->children[to->n_children++] = node; } + +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); + 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], + node->orientation[0], node->orientation[1], + node->orientation[2], node->orientation[3]); + node_mark_for_recalc(node); +} diff --git a/src/node.h b/src/node.h @@ -9,15 +9,14 @@ struct node { float rot[3]; float scale[3]; float mat[16]; - float local[16]; float orientation[4]; char *label; int needs_recalc; int n_children; - int mirrored; // TODO: make camera type + void (*custom_update)(struct node*); + void *custom_update_data; struct node* parent; struct node* children[MAX_NODE_CHILDREN]; - // TODO quaternion rot/orientation }; int node_recalc(struct node *root); @@ -25,6 +24,8 @@ void node_attach(struct node *node, struct node *to); void node_mark_for_recalc(struct node *node); struct node *node_init(struct node *node); void node_translate(struct node *node, float *p); +void node_forward(struct node *node, float *p); void node_rotate(struct node *node, float *p); +float *node_world(struct node *node); #endif /* POLYADVENT_NODE_H */ diff --git a/src/quat.c b/src/quat.c @@ -56,15 +56,45 @@ void quat_to_mat3(quat *quat, float *dest) { float wy = w*y2; float wz = w*z2; - dest[0] = 1 - (yy + zz); + dest[0] = 1.0 - (yy + zz); dest[1] = xy - wz; dest[2] = xz + wy; dest[3] = xy + wz; - dest[4] = 1 - (xx + zz); + dest[4] = 1.0 - (xx + zz); dest[5] = yz - wx; dest[6] = xz - wy; dest[7] = yz + wx; - dest[8] = 1 - (xx + yy); + dest[8] = 1.0 - (xx + yy); +} + +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]; + + // calculate quat * vec + float ix = qw*x + qy*z - qz*y; + float iy = qw*y + qz*x - qx*z; + float iz = qw*z + qx*y - qy*x; + float iw = -qx*x - qy*y - qz*z; + + // calculate result * inverse quat + dest[0] = ix*qw + iw*-qx + iy*-qz - iz*-qy; + dest[1] = iy*qw + iw*-qy + iz*-qx - ix*-qz; + dest[2] = iz*qw + iw*-qz + ix*-qy - iy*-qx; +} + +quat *quat_inverse(quat *q, quat *dest) { + if(!dest || q == dest) { + q[0] *= 1; + q[1] *= 1; + q[2] *= 1; + return q; + } + dest[0] = -q[0]; + dest[1] = -q[1]; + dest[2] = -q[2]; + dest[3] = q[3]; + return dest; } diff --git a/src/quat.h b/src/quat.h @@ -4,10 +4,13 @@ #define POLYADVENT_QUAT4_ typedef float quat; +#define QUAT(x,y,z,w) ((quat[4]){x,y,z,w}) void quat_id(quat *dest); void quat_multiply(quat *a, quat *b, quat *dest); void quat_axis_angle(float *axis, float angle, quat *dest); void quat_to_mat3(quat *quat, float *dest); +void quat_multiply_vec3(quat *quat, float *vec, float *dest); +quat *quat_inverse(quat *q, quat *dest); #endif /* POLYADVENT_QUAT4_ */ diff --git a/src/render.c b/src/render.c @@ -211,7 +211,6 @@ void render (struct game *game, struct geometry *geom) { struct node *player = &res->player; struct node *camera = &res->camera; - struct node *player_camera = &res->player_camera; float fade_factor = res->fade_factor; @@ -223,7 +222,9 @@ void render (struct game *game, struct geometry *geom) { /* printf("camera_pos %f %f %f", camera_pos[0], camera_pos[1], camera_pos[2]); */ /* mat4_print(camera->mat); */ /* node_recalc(&res->camera); */ - mat4_multiply(persp, camera->mat, mvp); + /* mat4_multiply(persp, camera->mat, mvp); */ + mat4_inverse(camera->mat, tmp_matrix); + mat4_multiply(persp, tmp_matrix, mvp); /* mat4_multiply(mvp, tmp_matrix, tmp_matrix); */ glUniform3f(res->uniforms.light_dir, light[0], light[1], light[2]); @@ -237,13 +238,6 @@ void render (struct game *game, struct geometry *geom) { /* mat4_print(player->mat); */ render_cube(res); - //player camera - - mat4_multiply(mvp, player_camera->mat, tmp_matrix); - glUniformMatrix4fv(res->uniforms.mvp, 1, 0, tmp_matrix); - /* mat4_multiply(persp, tmp_matrix, mvp); */ - render_cube(res); - // terrain glUniformMatrix4fv(res->uniforms.mvp, 1, 0, mvp); render_geom(res, geom, GL_TRIANGLES); diff --git a/src/update.c b/src/update.c @@ -16,35 +16,35 @@ static void movement(struct game *game, struct node *node) { amt *= 6; if (game->input.keystates[SDL_SCANCODE_A]) - node_translate(node, V3(-amt,0,0)); + node_forward(node, V3(-amt,0,0)); if (game->input.keystates[SDL_SCANCODE_E]) - node_translate(node, V3(0,0,amt)); + node_forward(node, V3(0,0,amt)); if (game->input.keystates[SDL_SCANCODE_Q]) - node_translate(node, V3(0,0,-amt)); + node_forward(node, V3(0,0,-amt)); if (game->input.keystates[SDL_SCANCODE_D]) - node_translate(node, V3(amt,0,0)); + node_forward(node, V3(amt,0,0)); if (game->input.keystates[SDL_SCANCODE_W]) - node_translate(node, V3(0,amt,0)); + node_forward(node, V3(0,amt,0)); if (game->input.keystates[SDL_SCANCODE_S]) - node_translate(node, V3(0,-amt,0)); + node_forward(node, V3(0,-amt,0)); // TODO: mark as update - if (game->input.keystates[SDL_SCANCODE_UP]) - node_rotate(node, V3(amt * 0.01,0,0)); + /* if (game->input.keystates[SDL_SCANCODE_UP]) */ + /* node_rotate(node, V3(amt * 0.01,0,0)); */ if (game->input.keystates[SDL_SCANCODE_RIGHT]) - node_rotate(node, V3(0, 0, -amt * 0.01)); + node_rotate(node, V3(0, 0, amt * 0.01)); if (game->input.keystates[SDL_SCANCODE_LEFT]) - node_rotate(node, V3(0, 0, amt * 0.01)); + node_rotate(node, V3(0, 0, -amt * 0.01)); - if (game->input.keystates[SDL_SCANCODE_DOWN]) - node_rotate(node, V3(-amt * 0.01, 0, 0)); + /* if (game->input.keystates[SDL_SCANCODE_DOWN]) */ + /* node_rotate(node, V3(-amt * 0.01, 0, 0)); */ if (game->input.keystates[SDL_SCANCODE_P]) mat4_print(node->mat); @@ -92,16 +92,18 @@ void update (struct game *game, u32 dt) { game->terrain->fn(game->terrain, res->player.pos[0], res->player.pos[1]) + PLAYER_HEIGHT; + node_recalc(&res->camera); + vec3_copy(res->player.pos, last_pos); + } - /* node_recalc(&res->root); */ - node_recalc(&res->root); - camera_follow(res->camera.pos, &res->player_camera.mat[M_X], res->camera.mat); - node_mark_for_recalc(&res->camera); - /* node_recalc(&res->camera); */ + node_recalc(&res->camera); + vec3 *camera_world = node_world(&res->camera); + float cam_terrain_z = + game->terrain->fn(game->terrain, camera_world[0], camera_world[1]); - /* movement(game, res->camera); */ - } + if (camera_world[2] < cam_terrain_z) + camera_world[2] = cam_terrain_z + 10.0; } if (game->input.keystates[SDL_SCANCODE_C]) {