polyadvent

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

commit a7be13b51009a4be98599820a03f1dc67144be8f
parent edcb70b6c188b1806153cccb1f1ef0ae8a52d144
Author: William Casarin <jb55@jb55.com>
Date:   Sun, 30 Jun 2019 10:45:36 -0700

dynamic nodes

Diffstat:
MTODOs.org | 10++++++++++
Msrc/animation.c | 51++++++++++++++++++++++++++++++++++++++++-----------
Msrc/animation.h | 10+++++-----
Msrc/camera.h | 2+-
Msrc/entity.c | 31+++++++++++++++++++++++++++----
Msrc/entity.h | 7++++---
Msrc/game.c | 47+++++++++++++++++++++++++++++++----------------
Msrc/game.h | 8++++----
Msrc/geometry.c | 5+++--
Msrc/main.c | 7++++---
Msrc/model.c | 10+++++++++-
Msrc/node.c | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Msrc/node.h | 38++++++++++++++++++++++++--------------
Msrc/orbit.c | 13++++++++-----
Msrc/orbit.h | 4++--
Msrc/render.c | 16++++++++++++----
Msrc/render.h | 7++++---
Msrc/resource.c | 28+++++++++++++++++++++++++---
Msrc/resource.h | 4+++-
Msrc/scene.c | 18+++++++++++-------
Msrc/terrain.c | 11+++++++----
Msrc/update.c | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Mtest/test_animation.c | 17++++++++++++++---
Mtest/test_resource.c | 22+++++++++++++++++-----
24 files changed, 404 insertions(+), 152 deletions(-)

diff --git a/TODOs.org b/TODOs.org @@ -17,6 +17,16 @@ To create a sense of movement CLOSED: [2019-06-22 Sat 12:52] ** DONE Load poses in engine CLOSED: [2019-06-22 Sat 12:52] + +** TODO factor node properties + +perhaps there's a more minimal subset of node that would be useful to +both joints and entities? + +** TODO use nodes for joints + +It will just be easier for interpolation + ** TODO Load bone weights ** TODO Run pose ** TODO Simple animation test diff --git a/src/animation.c b/src/animation.c @@ -2,6 +2,7 @@ #include <stdio.h> #include "xml.h" #include "util.h" +#include "node.h" #include "animation.h" enum dae_state { @@ -23,20 +24,35 @@ struct dae_data { void init_joint(struct joint *joint) { - memset(joint->children, -1, sizeof(joint->children)); joint->id = -1; - mat4_id(joint->mat); + joint->n_children_ids = 0; + for (int i = 0; i < MAX_JOINT_CHILDREN; i++) { + joint->children_ids[i] = -1; + } + init_id(&joint->node_id); } +void new_joint(struct joint *joint) +{ + init_joint(joint); + new_node(&joint->node_id); +} + + void init_pose(struct pose *pose) { pose->njoints = 0; + for (int i = 0; i < MAX_JOINTS; i++) { + init_joint(&pose->joints[i]); + } } static void parse_joint(const char *t, int id, struct joint *joint) { - float *m = joint->mat; - init_joint(joint); + struct node *node = get_node(&joint->node_id); + assert(node); + + float *m = node->mat; joint->id = id; /* printf(" parsing joint %d: %s\n", id, t); */ @@ -82,15 +98,27 @@ static void dae_tag_end(struct xmlparser *x, const char *t, size_t tl, int what) static void dae_tagbody(struct xmlparser *x, const char *d, size_t dl) { + static int count = 0; struct dae_data *data = (struct dae_data*)x->user_data; if (data->state == PARSING_JOINT_MATRIX) { assert(*data->nposes); + struct pose *pose = &data->poses[*data->nposes - 1]; + assert(pose); + struct joint *joint = &pose->joints[pose->njoints]; + assert(joint); + + struct node *node = new_node(&joint->node_id); + assert(node); + assert((int64_t)joint->node_id.uuid != -1); + assert(&joint->node_id == &pose->joints[pose->njoints].node_id); + parse_joint(d, pose->njoints, joint); - strncpy(joint->name, data->current_name, sizeof(data->current_name)); - joint->children[0] = data->node_level; + print_id(&joint->node_id); + node_set_label(node, data->current_name); + joint->children_ids[0] = data->node_level; pose->njoints++; data->state = PARSING_POSE; } @@ -135,18 +163,18 @@ static void process_joint_children(struct joint *joints, int njoints) joint = &joints[i]; // node level is stored in here on the first parser pass - int level = joint->children[0]; + int level = joint->children_ids[0]; for (int j = i+1; j < njoints; j++) { j2 = &joints[j]; - if (j2->children[0] == level + 1) { + if (j2->children_ids[0] == level + 1) { /* printf("%s(%d) assigning child %s(%d)\n", */ /* joint->name, level, j2->name, j2->children[0]); */ - assert(joint->nchildren+1 < MAX_JOINT_CHILDREN); - joint->children[joint->nchildren++] = j; + assert(joint->n_children_ids+1 < MAX_JOINT_CHILDREN); + joint->children_ids[joint->n_children_ids++] = j; } - else if (j2->children[0] <= level) + else if (j2->children_ids[0] <= level) break; } } @@ -183,5 +211,6 @@ void load_poses(const char *filename, struct pose *poses, int *nposes) process_joint_children(pose->joints, pose->njoints); } + fclose(data.dae_file); } diff --git a/src/animation.h b/src/animation.h @@ -3,6 +3,7 @@ #define POLYADVENT_ANIMATION_H #include "common.h" +#include "node.h" #define MAX_JOINT_CHILDREN 4 #define MAX_JOINTS 16 @@ -10,15 +11,13 @@ struct joint { - int children[MAX_JOINT_CHILDREN]; - int nchildren; int id; - char name[JOINT_LABEL_SIZE]; - float mat[MAT4_ELEMS]; + int children_ids[MAX_JOINT_CHILDREN]; + int n_children_ids; + node_id node_id; }; - struct pose { struct joint joints[MAX_JOINTS]; @@ -29,6 +28,7 @@ struct pose void load_poses(const char *filename, struct pose *poses, int *nposes); void init_joint(struct joint *joint); +void init_pose(struct pose *pose); #endif /* POLYADVENT_ANIMATION_H */ diff --git a/src/camera.h b/src/camera.h @@ -8,7 +8,7 @@ struct camera { float frustum[16]; - struct node node; + node_id node_id; }; void diff --git a/src/entity.c b/src/entity.c @@ -18,8 +18,16 @@ struct entity *get_all_entities(u32 *count, entity_id **ids) { return get_all_resources(&esys, count, ids); } -struct entity *init_entity(struct entity *ent) { - node_init(&ent->node); +struct entity *init_entity(struct entity *ent, node_id *id) { + node_id new_id; + if (id == NULL) { + init_id(&new_id); + new_node(&new_id); + ent->node_id = new_id; + } + else { + ent->node_id = *id; + } ent->casts_shadows = 1; return ent; } @@ -33,7 +41,12 @@ static inline struct entity *new_uninitialized_entity(entity_id *id) { } struct entity *new_entity(entity_id *id) { - return init_entity(new_uninitialized_entity(id)); + return new_entity_with_node(id, NULL); +} + + +struct entity *new_entity_with_node(entity_id *id, node_id *node) { + return init_entity(new_uninitialized_entity(id), node); } struct entity *add_entity(struct entity *e, entity_id *id) { @@ -53,7 +66,17 @@ void destroy_entities() { void destroy_entity(entity_id *id) { struct entity *ent = get_entity(id); - node_detach_from_parent(&ent->node); + assert(ent); + if (ent == NULL) + return; + + struct node *node = get_node(&ent->node_id); + assert(node); + if (node == NULL) + return; + + node_detach_from_parent(node); + destroy_resource(&esys, &ent->node_id); destroy_resource(&esys, id); } diff --git a/src/entity.h b/src/entity.h @@ -15,7 +15,7 @@ enum entity_flags { }; struct entity { - struct node node; + node_id node_id; struct model *model; u32 flags; float velocity[3]; @@ -25,14 +25,15 @@ struct entity { typedef struct resource_id entity_id; -struct entity *init_entity(struct entity *); +struct entity *init_entity(struct entity *, node_id *id); void destroy_entities(); struct resource_manager *_internal_get_entity_system(); void destroy_entity(entity_id *); void init_entity_system(); struct entity *get_entity(entity_id *); struct entity *get_all_entities(u32 *count, entity_id **ids); -struct entity *new_entity(entity_id *id); +struct entity *new_entity(entity_id *); +struct entity *new_entity_with_node(entity_id *, node_id *); void destroy_entity_system(); #endif /* ENTITY_H */ diff --git a/src/game.c b/src/game.c @@ -104,17 +104,27 @@ void game_init(struct game *game, int width, int height) { init_gl(&game->test_resources, width, height); init_entity_system(); init_model_manager(); + init_node_manager(); init_geometry_manager(); init_user_settings(&game->user_settings); check_gl(); struct resources *res = &game->test_resources; mat4 *mvp = res->test_mvp; - struct node *root = &res->root; - struct node *sun_camera = &res->sun_camera; + + init_id(&res->root_id); + init_id(&res->sun_camera_id); + init_id(&res->free_camera_id); + + struct node *root = new_node(&res->root_id); + struct node *sun_camera = new_node(&res->sun_camera_id); struct terrain *terrain = &game->terrain; struct entity *player; + assert(root->parent_id.generation == 0); + assert(root); + assert(sun_camera); + mat4 *light_dir = res->light_dir; int ok = 0; @@ -168,34 +178,39 @@ void game_init(struct game *game, int width, int height) { node_init(root); node_init(sun_camera); - init_orbit(&res->orbit_camera); - - root->label = "root"; + new_orbit(&res->orbit_camera); + node_set_label(root, "root"); // ENTITIES // player entity + init_id(&res->player_id); player = new_entity(&res->player_id); + struct node *pnode = get_node(&player->node_id); + assert(pnode); assert(res->player_id.index == 1); player->model = get_model(model_pirate_officer); - player->node.label = "player"; - node_attach(&player->node, root); - node_translate(&player->node, V3(terrain->size/2.,terrain->size/2.,0.0)); + node_set_label(pnode, "player"); + node_attach(&player->node_id, &res->root_id); + + assert(ideq(&pnode->parent_id, &res->root_id)); + + node_translate(pnode, V3(terrain->size/2.,terrain->size/2.,0.0)); // orbit camera - res->orbit_camera.coords.azimuth = -quat_yaw(player->node.orientation) - RAD(90.0); + res->orbit_camera.coords.azimuth = -quat_yaw(pnode->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; + res->camera_node_id = res->orbit_camera.node_id; // 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)); + struct node *freecam = new_node(&res->free_camera_id); + node_set_label(freecam, "freecam"); + node_attach(&res->free_camera_id, &player->node_id); + quat_axis_angle(V3(1,0,0), -45, freecam->orientation); + node_rotate(freecam, V3(100, 0, 0)); + node_translate(freecam, V3(0,-40,20)); input_init(&game->input); diff --git a/src/game.h b/src/game.h @@ -58,13 +58,13 @@ struct resources { gpu_addr vertex_attrs[n_vertex_attrs]; - struct node root; + node_id root_id; entity_id player_id; struct geometry qh_test; struct orbit orbit_camera; - struct node free_camera; - const struct node *camera_node; - struct node sun_camera; + node_id free_camera_id; + node_id camera_node_id; + node_id sun_camera_id; u32 test_cubemap; float time; diff --git a/src/geometry.c b/src/geometry.c @@ -167,8 +167,9 @@ make_buffer_geometry_(struct make_geometry *mkgeom, struct geometry *geom) { } void -make_buffer_geometry(struct make_geometry *mkgeom, geometry_id *geom_id) { - +make_buffer_geometry(struct make_geometry *mkgeom, geometry_id *geom_id) +{ + init_id(geom_id); struct geometry *geom = new_geometry(geom_id); make_buffer_geometry_(mkgeom, geom); diff --git a/src/main.c b/src/main.c @@ -71,7 +71,7 @@ int main(void) struct render_config fbo_render_config = { .draw_ui = 0, .is_depth_pass = 1, - .camera = game.test_resources.sun_camera.mat, + .camera = game.test_resources.sun_camera_id, .projection = game.test_resources.proj_ortho, .depth_vp = depth_vp }; @@ -79,7 +79,7 @@ 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_id, .projection = game.test_resources.proj_persp, .depth_vp = depth_vp }; @@ -93,10 +93,11 @@ int main(void) game.input.resized_height); handle_resize(&game, game.input.resized_width, game.input.resized_height); } - default_config.camera = game.test_resources.camera_node->mat; + //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; + update(&game); /* while (accumulator >= dt) { */ diff --git a/src/model.c b/src/model.c @@ -17,16 +17,24 @@ static struct resource_manager dyn_modelman; static int static_models_initialized = 0; struct model *init_model(struct model *model) { + init_id(&model->geom_id); model->shading = SHADING_VERT_COLOR; model->texture = 0; return model; } +struct model *new_model(struct model *model) +{ + init_model(model); + null_id(&model->geom_id); + return model; +} + static void initialize_static_models() { for (int i = 0; i < NUM_STATIC_MODELS; i++) { struct model_def *sm = &static_models[i]; assert(sm->id == i); - init_model(&sm->model); + new_model(&sm->model); } static_models_initialized = 1; } diff --git a/src/node.c b/src/node.c @@ -5,6 +5,36 @@ #include <string.h> #include <stdio.h> #include <assert.h> +#include <stdint.h> + +static struct resource_manager node_manager = {0}; + +static inline struct node *new_uninitialized_node(node_id *id) +{ + return new_resource(&node_manager, id); +} + +struct node *new_node(node_id *id) +{ + struct node *n = node_init(new_uninitialized_node(id)); + assert((int64_t)id->uuid != -1); + return n; +} + +struct node *get_node(node_id *id) +{ + return get_resource(&node_manager, id); +} + +void destroy_node(node_id *id) +{ + destroy_resource(&node_manager, id); +} + +void init_node_manager() +{ + init_resource_manager(&node_manager, sizeof(struct node), 128, 0xFFFF); +} struct node *node_init(struct node *node) { mat4_id(node->mat); @@ -14,9 +44,9 @@ struct node *node_init(struct node *node) { quat_id(node->orientation); node->n_children = 0; for (int i = 0; i < MAX_NODE_CHILDREN; ++i) - node->children[i] = NULL; + init_id(&node->children_ids[i]); node->flags = 0; - node->parent = NULL; + null_id(&node->parent_id); node_set_label(node, "unknown"); node->needs_recalc = 0; node->custom_update = 0; @@ -28,6 +58,11 @@ struct node *node_init(struct node *node) { int node_set_label(struct node *node, const char *label) { strncpy(node->label, label, sizeof(node->label)); + // return 0 if the string is too big and that we've truncated it + int ok = node->label[sizeof(node->label)-1] == '\0'; + // strncpy won't write this for large strings =/ + node->label[sizeof(node->label)-1] = '\0'; + return ok; } void node_scale(struct node *node, float val) { @@ -61,7 +96,8 @@ void node_rotate(struct node *node, vec3 *axis_angles) { int node_needs_recalc(struct node *node) { - return (node->parent && node->parent->needs_recalc) || node->needs_recalc; + struct node *parent = get_node(&node->parent_id); + return (parent && parent->needs_recalc) || node->needs_recalc; } vec3 *node_world(struct node *node) { @@ -77,13 +113,18 @@ void node_mark_for_recalc(struct node *node) { node->needs_recalc = 1; - for (int i = 0; i < node->n_children; ++i) - node_mark_for_recalc(node->children[i]); + for (int i = 0; i < node->n_children; ++i) { + struct node *child = get_node(&node->children_ids[i]); + if (child) + node_mark_for_recalc(child); + } } static void node_recalc_children(struct node *node) { for (int i = 0; i < node->n_children; ++i) { - node_recalc(node->children[i]); + struct node *child = get_node(&node->children_ids[i]); + if (child) + node_recalc(child); } } @@ -91,8 +132,9 @@ 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); + struct node *parent = get_node(&node->parent_id); + if (parent && node_needs_recalc(parent)) + node_recalc(parent); if (!node_needs_recalc(node)) { node_recalc_children(node); @@ -105,9 +147,9 @@ int node_recalc(struct node *node) { quat_to_mat3(node->orientation, rot); mat4_create_transform(node->pos, node->scale, rot, node->mat); - if (node->parent) { - assert(!node->parent->needs_recalc); - mat4_multiply(node->parent->mat, node->mat, node->mat); + if (parent) { + assert(!parent->needs_recalc); + mat4_multiply(parent->mat, node->mat, node->mat); } } @@ -122,10 +164,13 @@ int node_recalc(struct node *node) { int node_detach(struct node *node, struct node *from) { for (int i = 0; i < from->n_children; i++) { - if (from->children[i] == node) { - memmove(from->children[i], from->children[i+1], - from->n_children - i - 1); - assert(!"fixme, this should be times the size of *children"); + node_id *child_id = &from->children_ids[i]; + struct node *child = get_node(&from->children_ids[i]); + if (child && child == node) { + destroy_node(child_id); + memmove(&from->children_ids[i], &from->children_ids[i+1], + sizeof(*from->children_ids) * from->n_children - 1); + // TODO: test node_detach from->n_children--; return 1; } @@ -133,25 +178,38 @@ int node_detach(struct node *node, struct node *from) { return 0; } -void node_detach_from_parent(struct node *node) { - if (node->parent) - node_detach(node, node->parent); +void node_detach_from_parent(struct node *node) +{ + struct node *parent = get_node(&node->parent_id); + + if (parent) + node_detach(node, parent); } // count the total number of nodes -int node_count(struct node *node) { +int node_count(struct node *node) +{ int c = 1; for (int i = 0; i < node->n_children; i++) { - c += node_count(node->children[i]); + struct node *child = get_node(&node->children_ids[i]); + assert(child); + if (child) + c += node_count(child); } return c; } -void node_attach(struct node *node, struct node *to) { - assert(to->n_children <= MAX_NODE_CHILDREN); +void node_attach(struct resource_id *node_id, struct resource_id *to_id) +{ + struct node *node = get_node(node_id); + struct node *to = get_node(to_id); + + assert(node); + assert(to && to->n_children <= MAX_NODE_CHILDREN); - node->parent = to; - to->children[to->n_children++] = node; + node->parent_id = *to_id; + assert(node->parent_id.uuid == to_id->uuid); + to->children_ids[to->n_children++] = *node_id; } void node_forward(struct node *node, float *dir) { diff --git a/src/node.h b/src/node.h @@ -2,30 +2,35 @@ #ifndef POLYADVENT_NODE_H #define POLYADVENT_NODE_H +#include "resource.h" + #define MAX_NODE_CHILDREN 4 enum node_flags { NODE_IGNORE_RECALC = 1 << 0 }; +typedef struct resource_id node_id; + struct node { - float pos[3]; - float rot[3]; - float scale[3]; - float mat[16]; - float orientation[4]; - char label[8]; - int needs_recalc; - int flags; - int n_children; - void (*custom_update)(struct node*); - void *custom_update_data; - struct node* parent; - struct node* children[MAX_NODE_CHILDREN]; + float pos[3]; + float rot[3]; + float scale[3]; + float mat[16]; + float orientation[4]; + char label[8]; + int needs_recalc; + int flags; + int n_children; + void (*custom_update)(struct node*); + void *custom_update_data; + + node_id parent_id; + node_id children_ids[MAX_NODE_CHILDREN]; }; int node_recalc(struct node *root); -void node_attach(struct node *node, struct node *to); +void node_attach(node_id *node, node_id *to); int node_detach(struct node *node, struct node *from); void node_detach_from_parent(struct node *node); void node_mark_for_recalc(struct node *node); @@ -39,4 +44,9 @@ int node_count(struct node *node); float *node_world(struct node *node); int node_set_label(struct node *node, const char *label); +struct node *get_node(node_id *); +struct node *new_node(node_id *); +void destroy_node(node_id *); +void init_node_manager(); + #endif /* POLYADVENT_NODE_H */ diff --git a/src/orbit.c b/src/orbit.c @@ -49,10 +49,12 @@ vec3 *spherical_look_at(struct spherical *s, vec3 *target, mat4 *mat) { static void orbit_node_update(struct node *node) { - if (!node->parent) + struct node *parent = get_node(&node->parent_id); + + if (!parent) return; - float *a = node->parent->mat; + float *a = parent->mat; float *b = node->pos; float *dst = node->mat; @@ -71,9 +73,10 @@ static void orbit_node_update(struct node *node) { } -void init_orbit(struct orbit *orbit) { - node_init(&orbit->node); - orbit->node.label = "orbit_camera"; +void new_orbit(struct orbit *orbit) { + init_id(&orbit->node_id); + struct node *node = new_node(&orbit->node_id); + node_set_label(node, "orbcam"); /* orbit->node.custom_update = orbit_node_update; */ /* orbit->node.custom_update_data = orbit; */ } diff --git a/src/orbit.h b/src/orbit.h @@ -14,10 +14,10 @@ struct spherical { struct orbit { struct spherical coords; - struct node node; + node_id node_id; }; -void init_orbit(struct orbit *orbit); +void new_orbit(struct orbit *orbit); vec3 *spherical_dir(struct spherical s, vec3 *dir); vec3 *spherical_pos(struct spherical *s, vec3 *from, vec3 *to); diff --git a/src/render.c b/src/render.c @@ -260,7 +260,10 @@ void render (struct game *game, struct render_config *config) { mat4 *projection = config->projection; mat4 *light = res->light_dir; - const mat4 *camera = config->camera; + struct node *camera_node = get_node(&config->camera); + assert(camera_node); + + const mat4 *camera = camera_node->mat; u32 num_entities; struct entity *entities = @@ -331,8 +334,13 @@ void render (struct game *game, struct render_config *config) { res->sun_color[2]); check_gl(); - mat4_multiply(view_proj, entity->node.mat, mvp); - mat4_copy(entity->node.mat, model_view); + struct node *node = get_node(&entity->node_id); + assert(node); + if (node == NULL) + return; + + mat4_multiply(view_proj, node->mat, mvp); + mat4_copy(node->mat, model_view); mat4_multiply(config->depth_vp, model_view, depth_mvp); glUniformMatrix4fv(res->uniforms.depth_mvp, 1, 0, depth_mvp); check_gl(); @@ -340,7 +348,7 @@ void render (struct game *game, struct render_config *config) { glUniformMatrix4fv(res->uniforms.mvp, 1, 0, mvp); check_gl(); - glUniformMatrix4fv(res->uniforms.model, 1, 0, entity->node.mat); + glUniformMatrix4fv(res->uniforms.model, 1, 0, node->mat); check_gl(); recalc_normals(res->uniforms.normal_matrix, model_view, normal_matrix); diff --git a/src/render.h b/src/render.h @@ -2,15 +2,16 @@ #define POLYADVENT_RENDER_H #include "geometry.h" +#include "node.h" struct game; struct render_config { int draw_ui; int is_depth_pass; - const float *camera; - float *projection; - float *depth_vp; + node_id camera; + float* projection; + float* depth_vp; }; void init_gl(struct resources *resources, int width, int height); diff --git a/src/resource.c b/src/resource.c @@ -11,6 +11,7 @@ static u64 resource_uuids = 0; static inline void *index_resource(struct resource_manager *r, int i) { unsigned char *p = r->resources; + assert(p); return p + (i * r->elem_size); } @@ -24,12 +25,19 @@ void *get_all_resources(struct resource_manager *r, u32 *count, struct resource_ return r->resources; } -void init_resource_id(struct resource_id *id) { +void init_id(struct resource_id *id) { id->index = -1; id->generation = -1; id->uuid = -1; } +void null_id(struct resource_id *id) +{ + id->generation = 0; + id->uuid = -1; + id->index = -1; +} + void init_resource_manager(struct resource_manager *r, u32 elem_size, u32 initial_elements, u32 max_elements) { r->generation = 1; @@ -118,8 +126,16 @@ static void resize(struct resource_manager *r) r->generation += 2; } +void print_id(struct resource_id *id) +{ + printf("res_id(uuid:%llu ind:%d gen:%d)\n", id->uuid, id->index, id->generation); +} + void *new_resource(struct resource_manager *r, struct resource_id *id) { + assert(id); + assert((int)id->index == -1 && "res_id already initialized or uninitialized"); + struct resource_id *fresh_id; if (r->resource_count + 1 > r->max_capacity) @@ -139,13 +155,19 @@ void *new_resource(struct resource_manager *r, struct resource_id *id) } void *get_resource(struct resource_manager *r, struct resource_id *id) { - if (id->generation == 0) + assert((int64_t)id->generation != -1 && "id intialized but not allocated (needs new_ call)"); + + if (id->generation == 0) { + //unusual("getting already deleted resource %llu\n", id->uuid); return NULL; + } enum refresh_status res = refresh_id(r, id, id); - if (res == RESOURCE_DELETED) + if (res == RESOURCE_DELETED) { + unusual("getting deleted resource %llu\n", id->uuid); return NULL; + } return index_resource(r, id->index); } diff --git a/src/resource.h b/src/resource.h @@ -29,12 +29,14 @@ struct resource_manager { #define ideq(a, b) ((a)->uuid == (b)->uuid) -void init_resource_id(struct resource_id *id); +void init_id(struct resource_id *id); void *get_resource(struct resource_manager *r, struct resource_id *id); void *get_all_resources(struct resource_manager *, u32 *count, struct resource_id **ids); void destroy_resource(struct resource_manager *, struct resource_id *id); void destroy_resource_manager(struct resource_manager *); void *new_resource(struct resource_manager *, struct resource_id *id); +void print_id(struct resource_id *); +void null_id(struct resource_id *id); void init_resource_manager(struct resource_manager *r, u32 elem_size, u32 initial_elements, u32 max_elements); diff --git a/src/scene.c b/src/scene.c @@ -26,14 +26,18 @@ void default_scene(struct game *game) { player->flags &= ~ENT_INVISIBLE; struct entity *tower = new_entity(NULL); + struct node *tnode = get_node(&tower->node_id); + struct node *pnode = get_node(&player->node_id); + + assert(tnode); tower->model = get_model(model_tower); - tower->node.label = "tower"; - node_attach(&tower->node, &player->node); - node_translate(&tower->node, V3(0.0, 50.0, 0.0)); - node_recalc(&tower->node); - float z = terrain->fn(terrain, tower->node.mat[M_X], tower->node.mat[M_Y]); - node_detach(&tower->node, &player->node); - tower->node.mat[M_Z] = z; + node_set_label(tnode, "tower"); + node_attach(&tower->node_id, &player->node_id); + node_translate(tnode, V3(0.0, 50.0, 0.0)); + node_recalc(tnode); + float z = terrain->fn(terrain, tnode->mat[M_X], tnode->mat[M_Y]); + node_detach(tnode, pnode); + tnode->mat[M_Z] = z; // END ENTITIES diff --git a/src/terrain.c b/src/terrain.c @@ -52,17 +52,20 @@ void reset_terrain(struct terrain *terrain, float size) { } void init_terrain(struct terrain *terrain, float size) { - struct entity *ent; + init_id(&terrain->entity_id); + struct entity *ent = new_entity(&terrain->entity_id); + struct node *node = get_node(&ent->node_id); - ent = new_entity(&terrain->entity_id); + assert(node); assert(terrain->entity_id.index == 0); + terrain->model.shading = SHADING_TERRAIN; ent->model = &terrain->model; - ent->node.label = "terrain_node"; + node_set_label(node, "terrain"); ent->casts_shadows = 0; // this is scale for some reason!? - ent->node.pos[2] = 20.0; + node->pos[2] = 20.0; reset_terrain(terrain, size); } diff --git a/src/update.c b/src/update.c @@ -10,8 +10,10 @@ #include "uniform.h" #include "game.h" #include "mat_util.h" +#include "resource.h" #include "shader.h" #include "file.h" +#include "debug.h" #include <math.h> static void movement(struct game *game, struct node *node, float speed_mult) { @@ -93,9 +95,10 @@ void update_terrain(struct terrain *terrain) { struct entity *ent = get_entity(&terrain->entity_id); assert(ent); struct perlin_settings *ts = &terrain->settings; - struct node *tnode = &ent->node; + struct node *tnode = get_node(&ent->node_id); + assert(tnode); - printf("updating terrain\n"); + debug("updating terrain\n"); if (first) { reset_terrain(terrain, terrain->size); @@ -137,24 +140,25 @@ void update_terrain(struct terrain *terrain) { static void player_terrain_collision(struct terrain *terrain, struct entity *player) { // player movement static vec3 last_pos[3] = {0}; + struct node *node = get_node(&player->node_id); - if (!vec3_eq(player->node.pos, last_pos, 0.0001)) { - float player_z = player->node.pos[2]; + if (!vec3_eq(node->pos, last_pos, 0.0001)) { + float player_z = node->pos[2]; float terrain_z = - terrain->fn(terrain, player->node.pos[0], player->node.pos[1]); + terrain->fn(terrain, node->pos[0], node->pos[1]); float inset = min(0.0, player_z - terrain_z); if (inset <= 0) - node_translate(&player->node, V3(0.0, 0.0, -inset)); + node_translate(node, V3(0.0, 0.0, -inset)); } } -static void player_movement(struct game *game, struct entity *player) { - movement(game, &player->node, 2.0); +static void player_movement(struct game *game, struct node *player_node) { + movement(game, player_node, 2.0); } @@ -224,6 +228,10 @@ static void day_night_cycle(float time, struct resources *res) { float val = time * 0.0001; float intensity = 1.0;//max(0.0, vec3_dot(res->light_dir, V3(0.0, 0.0, 1.0))); */ struct entity *player = get_player(res); + struct node *pnode = get_node(&player->node_id); + assert(pnode); + struct node *suncam = get_node(&res->sun_camera_id); + assert(suncam); float light_pos[3]; @@ -258,30 +266,37 @@ static void day_night_cycle(float time, struct resources *res) { /* printf("intensity %f(%f) n %f light_dir %f %f\n", roots, intensity, */ /* n, res->light_dir[1], res->light_dir[2]); */ - vec3_add(player->node.pos, res->light_dir, light_pos); + vec3_add(pnode->pos, res->light_dir, light_pos); /* float target[3]; */ /* float hh = player->model.geom.max[2] / 2.0; */ /* vec3_copy(player->node.pos, target); */ /* target[2] += 2.0; */ - look_at(light_pos, player->node.pos, V3(0, 0, 1.0), res->sun_camera.mat); + look_at(light_pos, pnode->pos, V3(0, 0, 1.0), suncam->mat); /* look_at(light_pos, player->node.pos, V3(0, 0, 1.0), res->sun_camera.mat); */ } static void gravity(struct game *game) { struct entity *player = get_player(&game->test_resources); + struct node *pnode = get_node(&player->node_id); + assert(pnode); - node_translate(&player->node, V3(0.0, 0.0, -1.0)); + node_translate(pnode, V3(0.0, 0.0, -1.0)); } void orbit_update_from_mouse(struct orbit *camera, struct input *input, float mouse_sens, struct entity *player, - float dt) { + float dt) +{ float target[3]; - struct node *target_node = &player->node; + struct node *target_node = get_node(&player->node_id); + struct node *cam_node = get_node(&camera->node_id); struct geometry *player_geom = get_geometry(&player->model->geom_id); + assert(target_node); + assert(cam_node); + node_recalc(target_node); vec3_copy(node_world(target_node), target); vec3_add(target, V3(0.0, 0.0, player_geom->max[2] * 2.0), target); @@ -315,7 +330,7 @@ void orbit_update_from_mouse(struct orbit *camera, struct input *input, /* camera->coords.inclination, */ /* camera->coords.radius); */ - spherical_look_at(&camera->coords, target, camera->node.mat); + spherical_look_at(&camera->coords, target, cam_node->mat); } @@ -339,19 +354,23 @@ static void player_update(struct game *game, struct entity *player) { struct resources *res = &game->test_resources; struct orbit *camera = &res->orbit_camera; + struct node *node = get_node(&player->node_id); + struct node *cam_node = get_node(&res->camera_node_id); + assert(node); + assert(cam_node); orbit_update_from_mouse(camera, &game->input, game->user_settings.mouse_sens, player, game->dt); - camera_keep_above_ground(&game->terrain, res->camera_node); + camera_keep_above_ground(&game->terrain, cam_node); // move player camera toward camera orientation if (input_is_dragging(&game->input, SDL_BUTTON_RIGHT)) { 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); + quat_axis_angle(V3(0.0, 0.0, 1.0), -yaw - RAD(90), node->orientation); } player_terrain_collision(&game->terrain, player); - node_recalc(&player->node); + node_recalc(node); } @@ -359,10 +378,18 @@ static void player_update(struct game *game, struct entity *player) { void update (struct game *game) { static int toggle_fog = 0; static int first = 1; - struct resources *res = &game->test_resources; - struct terrain *terrain = &game->terrain; - struct node *root = &game->test_resources.root; - struct entity *player = get_player(res); + struct resources *res = &game->test_resources; + struct terrain *terrain = &game->terrain; + struct node *root = get_node(&game->test_resources.root_id); + struct entity *player = get_player(res); + struct node *pnode = get_node(&player->node_id); + struct node *cam_node = get_node(&res->camera_node_id); + struct node *freecam_node = get_node(&res->free_camera_id); + + assert(pnode); + assert(cam_node); + assert(freecam_node); + float *time = &res->time; float *light = res->light_dir; @@ -377,12 +404,15 @@ void update (struct game *game) { /* vec3_scale(camera_dir, -1, camera_dir); */ if (game->input.modifiers & KMOD_LALT) { - if (res->camera_node == &res->free_camera) - movement(game, &res->free_camera, 1.0); + if (ideq(&res->camera_node_id, &res->free_camera_id)) + movement(game, freecam_node, 1.0); } else { - player_movement(game, player); + player_movement(game, pnode); } + + assert(root->parent_id.generation == 0); + player_update(game, player); if (was_key_pressed_this_frame(game, SDL_SCANCODE_R)) @@ -395,10 +425,10 @@ void update (struct game *game) { 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; + if (!ideq(&res->camera_node_id, &res->free_camera_id)) + res->camera_node_id = res->free_camera_id; else - res->camera_node = &res->orbit_camera.node; + res->camera_node_id = res->orbit_camera.node_id; } if (toggle_fog) { diff --git a/test/test_animation.c b/test/test_animation.c @@ -9,9 +9,16 @@ int main(int argc, char *argv[]) { struct pose *pose; struct joint *joint; + struct node *node; struct pose poses[4]; int nposes; + init_node_manager(); + + for (int i = 0; i < (int)ARRAY_SIZE(poses); i++) { + init_pose(&poses[i]); + } + load_poses("data/models/pirate-officer.dae", poses, &nposes); assert(nposes == 1); @@ -19,12 +26,16 @@ int main(int argc, char *argv[]) assert(pose->njoints == 11); joint = &pose->joints[0]; - assert(approxeq(joint->mat[0], 0.999897)); + node = get_node(&joint->node_id); + assert(node); + assert(approxeq(node->mat[0], 0.999897)); joint = &pose->joints[1]; - assert(approxeq(joint->mat[1], -0.01434187)); + node = get_node(&joint->node_id); + assert(node); + assert(approxeq(node->mat[1], -0.01434187)); - assert(pose->joints[0].nchildren == 3); + assert(pose->joints[0].n_children_ids == 3); return 0; } diff --git a/test/test_resource.c b/test/test_resource.c @@ -2,6 +2,7 @@ #include "resource.h" #include "entity.h" #include "model.h" +#include "util.h" #include "debug.h" #include <assert.h> @@ -9,29 +10,34 @@ void test_compact() { printf("test_compact\n"); struct resource_manager r; - struct resource_id id, first_id; + struct resource_id ids[3], first_id; int *p; init_resource_manager(&r, sizeof(int), 2, 4); + for (int i = 0; i < (int)ARRAY_SIZE(ids); i++) + init_id(&ids[i]); + + init_id(&first_id); + p = new_resource(&r, &first_id); assert(r.resource_count == 1); *p = 11; - p = new_resource(&r, &id); + p = new_resource(&r, &ids[0]); *p = 22; assert(r.resource_count == 2); destroy_resource(&r, &first_id); assert(r.resource_count == 1); assert(get_resource(&r, &first_id) == NULL); - assert(*(int*)get_resource(&r, &id) == 22); + assert(*(int*)get_resource(&r, &ids[0]) == 22); - new_resource(&r, &id); + new_resource(&r, &ids[1]); assert(r.resource_count == 2); assert(r.current_capacity == 2); - new_resource(&r, &id); + new_resource(&r, &ids[2]); assert(r.resource_count == 3); assert(r.current_capacity >= 3); } @@ -46,6 +52,9 @@ void test_int_resource_manager() // 2 item case init_resource_manager(&r, sizeof(int), 1, 2); + init_id(&id); + init_id(&first_id); + p = new_resource(&r, &first_id); assert(p); *p = 42; @@ -73,8 +82,11 @@ void test_entity_system() entity_id ent_id; entity_id *ids; + init_node_manager(); init_entity_system(); + init_id(&ent_id); + ents = get_all_entities(&count, &ids); assert(count == 0);