polyadvent

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

commit fe404d05973bd84e45bc4f24e871cd777ae16d5c
parent ab66e332265639a252e3d3c9b679b64b04836ac1
Author: William Casarin <jb55@jb55.com>
Date:   Mon, 30 Apr 2018 14:28:01 -0700

scene graph improvements

Diffstat:
Msrc/camera.c | 8++++----
Msrc/camera.h | 2+-
Msrc/game.c | 22++++++++++++++++++++--
Msrc/game.h | 3++-
Msrc/mat4.c | 37+++++++++++++++++++++++++++++++++++++
Msrc/mat4.h | 2++
Msrc/node.c | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Msrc/node.h | 14+++++++++++---
Msrc/render.c | 14+++++++++++---
Msrc/update.c | 33+++++++++++++++++++++++----------
Msrc/vec3.c | 13+++++++++++++
Msrc/vec3.h | 2++
12 files changed, 183 insertions(+), 30 deletions(-)

diff --git a/src/camera.c b/src/camera.c @@ -11,15 +11,15 @@ struct camera *camera_init(struct camera *cam) { void -camera_follow(vec3 *cam_pos, vec3 *target_prev, vec3 *target, mat4 *cam) { - cam_pos[0] = target[0]; +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] + 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]); */ - /* look_at(cam_pos, target, V3(0,1,0), cam); */ + look_at(cam_pos, target, V3(0,1,0), cam); /* cam_pos[0] = -target[0]; */ /* cam_pos[1] = -target[1]; */ /* cam_pos[2] = target[2]; */ diff --git a/src/camera.h b/src/camera.h @@ -12,6 +12,6 @@ struct camera { }; void -camera_follow(vec3 *cam_pos, vec3 *target_prev, vec3 *target, mat4 *cam); +camera_follow(vec3 *cam_pos, vec3 *target, mat4 *cam); #endif /* POLYADVENT_CAMERA_H */ diff --git a/src/game.c b/src/game.c @@ -12,8 +12,10 @@ mat4 *cam_init = (float[16]){ 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; @@ -23,17 +25,33 @@ void game_init(struct game *game) { light_dir[1] = 1; light_dir[2] = 0.8; + 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); + /* vec3_all(camera->scale, -1); */ camera->mirrored = 1; node_translate(player, V3(10,10,0)); - node_translate(camera, V3(50,0,20)); + node_translate(camera, V3(0,0,20)); + node_translate(player_camera, V3(10,10,20)); + /* node_recalc(camera); */ - camera->rot[0] = -45; + /* player_camera->mirrored = 1; */ + /* camera->parent = player_camera; */ + camera->rot[0] = 45; // 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 @@ -30,11 +30,12 @@ struct resources { gpu_addr normal; } attributes; + struct node root; struct node player; + struct node player_camera; struct node camera; struct node terrain_node; - float normal_matrix[MAT4_ELEMS]; float test_mvp[MAT4_ELEMS]; float light_dir[3]; float camera_persp[MAT4_ELEMS]; diff --git a/src/mat4.c b/src/mat4.c @@ -327,3 +327,40 @@ void mat4_print(const mat4 *m) { } printf("\n"); } + +/* mat4 *mat4_create_transform(float *pos, float *scale, float *rot, mat4 *dest) { */ +/* if (!dest) { dest = mat4.create(); } */ + +/* float halfAngle = 0.5*angle; */ +/* float sin_ = sin(halfAngle); */ + +/* dest[0] = sin_*axis[0]; */ +/* dest[1] = sin_*axis[1]; */ +/* dest[2] = sin_*axis[2]; */ +/* dest[3] = cos(halfAngle); */ + +/* var rot = quat4.toMat3(orientation); */ + +/* dest[0] = scale[0] * rot[0]; */ +/* dest[1] = scale[0] * rot[1]; */ +/* dest[2] = scale[0] * rot[2]; */ +/* dest[3] = 0; */ + +/* dest[4] = scale[1] * rot[3]; */ +/* dest[5] = scale[1] * rot[4]; */ +/* dest[6] = scale[1] * rot[5]; */ +/* dest[7] = 0; */ + +/* dest[8] = scale[2] * rot[6]; */ +/* dest[9] = scale[2] * rot[7]; */ +/* dest[10] = scale[2] * rot[8]; */ +/* dest[11] = 0; */ + +/* dest[12] = position[0]; */ +/* dest[13] = position[1]; */ +/* dest[14] = position[2]; */ +/* dest[15] = 1; */ + +/* return dest; */ +/* } */ +/* } */ diff --git a/src/mat4.h b/src/mat4.h @@ -5,6 +5,8 @@ typedef float mat4; #define M_Y 13 #define M_Z 14 + +/* mat4 *mat4_create_transform(mat4 *a, float *pos, float *scale, float *rot); */ mat4 *mat4_scale(mat4 *a, float v[3], mat4 *out); mat4 *mat4_frustum (float left, float right, float bottom, float top, float near, float far, mat4 *dest); diff --git a/src/node.c b/src/node.c @@ -4,15 +4,22 @@ #include "mat4.h" #include "vec3.h" #include <stdio.h> +#include <assert.h> struct node *node_init(struct node *node) { mat4_id(node->mat); vec3_all(node->pos, 0); vec3_all(node->rot, 0); vec3_all(node->scale, 1.0); - node->children = 0; + 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_mark_for_recalc(node); + return node; } @@ -22,17 +29,47 @@ void node_translate(struct node *node, vec3 *p) { /* printf("translating %f %f %f\n", p[0], p[1], p[2]); */ vec3_add(node->pos, p, node->pos); + node_mark_for_recalc(node); +} + +int node_needs_recalc(struct node *node) { + return (node->parent && node->parent->needs_recalc) || node->needs_recalc; +} + +void node_mark_for_recalc(struct node *node) { + static int j = 0; + + if (node->needs_recalc) + return; + 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); + node_mark_for_recalc(node->children[i]); + } +} + +static void node_recalc_children(struct node *node) { + for (int i = 0; i < node->n_children; ++i) { + node_recalc(node->children[i]); + } } int node_recalc(struct node *node) { float rotate_axis[3]; + float tmp[16]; - if (!node->needs_recalc) - return 0; + assert(node); - mat4_id(node->mat); + if (!node_needs_recalc(node)) { + // XXX: do I need this? + goto recalc_children; + } + printf("recalculating %s\n", node->label); + + mat4_id(node->mat); node->needs_recalc = 0; @@ -54,7 +91,7 @@ int node_recalc(struct node *node) { 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], rotate_axis, 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); } @@ -64,10 +101,24 @@ int node_recalc(struct node *node) { 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); */ + if (node->parent) { + assert(!node->parent->needs_recalc); + mat4_multiply(node->mat, node->parent->mat, node->mat); + } + +recalc_children: + node_recalc_children(node); + return 1; } + +void node_attach(struct node *node, struct node *to) { + assert(to->n_children <= MAX_NODE_CHILDREN); + + node->parent = to; + to->children[to->n_children++] = node; +} diff --git a/src/node.h b/src/node.h @@ -2,18 +2,26 @@ #ifndef POLYADVENT_NODE_H #define POLYADVENT_NODE_H +#define MAX_NODE_CHILDREN 4 + struct node { float pos[3]; float rot[3]; float scale[3]; float mat[16]; + float orientation[4]; + char *label; int needs_recalc; + int n_children; int mirrored; // TODO: make camera type - struct node* children; - // TODO quaternion rotation + struct node* parent; + struct node* children[MAX_NODE_CHILDREN]; + // TODO quaternion rot/orientation }; -int node_recalc(struct node *node); +int node_recalc(struct node *root); +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); diff --git a/src/render.c b/src/render.c @@ -206,11 +206,12 @@ void render (struct game *game, struct geometry *geom) { struct resources *res = &game->test_resources; mat4 *mvp = res->test_mvp; - mat4 *normal = res->normal_matrix; mat4 *persp = res->camera_persp; mat4 *light = res->light_dir; + struct node *player = &res->player; struct node *camera = &res->camera; + struct node *player_camera = &res->player_camera; float fade_factor = res->fade_factor; @@ -220,8 +221,8 @@ void render (struct game *game, struct geometry *geom) { /* v3[1] = fade_factor * 1.4f; */ /* mat4_rotate(mvp, 0.004f, v3, mvp); */ /* printf("camera_pos %f %f %f", camera_pos[0], camera_pos[1], camera_pos[2]); */ - node_recalc(camera); /* mat4_print(camera->mat); */ + /* node_recalc(&res->camera); */ mat4_multiply(persp, camera->mat, mvp); /* mat4_multiply(mvp, tmp_matrix, tmp_matrix); */ @@ -230,10 +231,17 @@ void render (struct game *game, struct geometry *geom) { glUniform1f(res->uniforms.tscale, res->uniforms.tscale); //player - node_recalc(player); mat4_multiply(mvp, player->mat, tmp_matrix); glUniformMatrix4fv(res->uniforms.mvp, 1, 0, tmp_matrix); /* mat4_multiply(persp, tmp_matrix, mvp); */ + /* 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 diff --git a/src/update.c b/src/update.c @@ -9,7 +9,7 @@ #include "poisson.h" #include "uniform.h" -void movement(struct game *game, struct node *node) { +static void movement(struct game *game, struct node *node) { float amt = 0.25; if (game->input.modifiers & KMOD_SHIFT) @@ -33,6 +33,7 @@ void movement(struct game *game, struct node *node) { if (game->input.keystates[SDL_SCANCODE_S]) node_translate(node, V3(0,-amt,0)); + // TODO: mark as update if (game->input.keystates[SDL_SCANCODE_UP]) node->rot[0] += amt * 0.01; @@ -61,6 +62,7 @@ void update (struct game *game, u32 dt) { struct perlin_settings *ts = &game->terrain->settings; float player_prev[MAT4_ELEMS]; struct node *tnode = &game->test_resources.terrain_node; + struct node *root = &game->test_resources.root; float *light = res->light_dir; if (first) { @@ -73,23 +75,33 @@ void update (struct game *game, u32 dt) { movement(game, &res->camera); /* mat4_multiply(res->player, res->ca era, res->player); */ } - if (game->input.modifiers & KMOD_LCTRL) { + else if (game->input.modifiers & KMOD_LCTRL) { movement(game, &res->terrain_node); /* mat4_multiply(res->player, res->ca era, res->player); */ } else { - movement(game, &res->player); /* mat4_copy(res->player, player_prev); */ + static vec3 last_pos[3] = {0}; + + movement(game, &res->player); + + if (!vec3_eq(res->player.pos, last_pos, 0.0001)) { + printf("else\n"); - res->player.pos[2] = - game->terrain->fn(game->terrain, res->player.pos[0], res->player.pos[1]) + + res->player.pos[2] = + game->terrain->fn(game->terrain, res->player.pos[0], res->player.pos[1]) + PLAYER_HEIGHT; - res->player.needs_recalc = 1; - node_recalc(&res->camera); - camera_follow(res->camera.pos, res->player.pos, res->player.pos, res->camera.mat); - res->camera.needs_recalc = 1; - /* movement(game, 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); */ + + /* movement(game, res->camera); */ + } } if (game->input.keystates[SDL_SCANCODE_C]) { @@ -176,4 +188,5 @@ void update (struct game *game, u32 dt) { } + node_recalc(root); } diff --git a/src/vec3.c b/src/vec3.c @@ -223,3 +223,16 @@ int vec3_isall(vec3 *vec, float n) { return 1; } + +int vec3_eq(vec3 *a, vec3 *b, float precision) { + return fabs(a[0] - b[0]) <= precision && + fabs(a[1] - b[1]) <= precision && + fabs(a[2] - b[2]) <= precision; +} + + +void vec3_copy(vec3 *a, vec3 *dest) { + dest[0] = a[0]; + dest[1] = a[1]; + dest[2] = a[2]; +} diff --git a/src/vec3.h b/src/vec3.h @@ -20,3 +20,5 @@ float vec3_dot(vec3 *vec, vec3 *vec2); int vec3_isall(vec3 *vec, float n); vec3 *vec3_all(vec3 *vec, float n); vec3 *vec3_add(vec3 *vec, vec3 *vec2, vec3 *dest); +int vec3_eq(vec3 *a, vec3 *b, float precision); +void vec3_copy(vec3 *a, vec3 *dest);