cepheid

An Aurora 4X clone
Log | Files | Refs | README

commit 58377c23450c9213e10d599df096dce0dca1263e
parent ce2c86eaba85fe239a2a77581b716e3b5eb0fb21
Author: hhvn <dev@hhvn.uk>
Date:   Tue,  4 Oct 2022 17:52:24 +0100

Tree structure

Diffstat:
Msrc/main.c | 10++++++++++
Msrc/main.h | 6++++++
Msrc/save.c | 3++-
Msrc/struct.h | 27++++++++++++++++++++++-----
Msrc/system.c | 65++++++++++++++++++++++++++++++++++++-----------------------------
Asrc/tree.c | 146+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/ui.c | 2+-
Msrc/ui/bodies.c | 28+++++++++++++++++-----------
Msrc/ui/main.c | 10+++++-----
9 files changed, 245 insertions(+), 52 deletions(-)

diff --git a/src/main.c b/src/main.c @@ -7,6 +7,16 @@ Save *save = NULL; +void +warning(char *fmt, ...) { + va_list ap; + + fprintf(stderr, "warning: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + int main(void) { int view_prev; diff --git a/src/main.h b/src/main.h @@ -18,6 +18,7 @@ /* main.c */ extern Save *save; +void warning(char *fmt, ...); /* str.c */ void * falloc(size_t size); @@ -38,6 +39,11 @@ void edittrunc(wchar_t *str, int *len, int *cur); void editrm(wchar_t *str, int *len, int *cur); void editins(wchar_t *str, int *len, int *cur, int size, wchar_t c); +/* tree.c */ +Tree * tree_add_child(Tree *t, char *name, int type, void *data, Tree **ptr); +int tree_delete(Tree **t, int freedata); +int tree_delete_r(Tree **t, int freedata); + /* ui.c */ #define VIEWS_MAX_WIDTH (UI_VIEW_LAST*100) #define VIEWS_HEIGHT 25 diff --git a/src/save.c b/src/save.c @@ -28,7 +28,6 @@ save_read(Loader *lscr, char *name) { char dir[PATH_MAX]; char *str; - if (save) save_free(); @@ -37,6 +36,8 @@ save_read(Loader *lscr, char *name) { snprintf(dir, sizeof(dir), "%s/%s", SAVEDIR, name); + memset(&save->systems, 0, sizeof(save->systems)); + loading_update(lscr, "Initializing DB"); dbdeclare(dir); save->db.dir = nstrdup(dir); diff --git a/src/struct.h b/src/struct.h @@ -1,7 +1,25 @@ #include <stddef.h> #include <sys/types.h> +/* tree.c */ +typedef struct Tree Tree; +struct Tree { + Tree *p; /* previous */ + char *name; + int collapsed; /* matters for Treeview */ + int type; + void *data; + Tree *u; /* up */ + Tree *d; /* down */ + Tree *n; /* next */ +}; + /* system.c */ +enum { + SYSTREE_SYS, + SYSTREE_BODY, +}; + typedef struct { float r; float theta; @@ -27,6 +45,7 @@ enum BodyType { typedef struct Body Body; struct Body { + Tree *t; Body *parent; Polar polar; Vector2 vector; @@ -55,8 +74,7 @@ struct Body { typedef struct { char *name; - Body **bodies; - size_t bodies_len; + Tree *t; Body *furthest_body; struct { int stars; @@ -77,8 +95,7 @@ typedef struct { char *systems; char *fleets; } db; - System *systems; - size_t systems_len; + Tree systems; System *homesys; } Save; @@ -137,7 +154,7 @@ typedef struct { } Checkbox; typedef struct { - char *name; + char *label; void (*func)(int); int arg; } Button; diff --git a/src/system.c b/src/system.c @@ -80,8 +80,7 @@ sys_init(char *name) { System *ret = malloc(sizeof(System)); if (!ret) return NULL; ret->name = nstrdup(name); - ret->bodies = NULL; - ret->bodies_len = 0; + ret->t = NULL; ret->furthest_body = NULL; memset(&ret->num, 0, sizeof(ret->num)); return ret; @@ -102,6 +101,7 @@ filter_bodyinsystem(void *data, char *path) { System * sys_load(System *s, char *name) { char *dir, *tmp; + Body **bodies; char **bname; char **bparent; size_t blen, i; @@ -113,24 +113,24 @@ sys_load(System *s, char *name) { s->lypos.y = strnum(dbget(save->db.systems, name, "y")); dir = smprintf("%s/", s->name); - s->bodies_len = blen = dblistgroups_f(&bname, save->db.systems, &filter_bodyinsystem, dir); + blen = dblistgroups_f(&bname, save->db.systems, &filter_bodyinsystem, dir); if (!bname) return NULL; bparent = malloc(sizeof(char *) * blen); - s->bodies = malloc(sizeof(Body *) * blen); + bodies = malloc(sizeof(Body *) * blen); - if (!bparent || !s->bodies) + if (!bparent || !bodies) return NULL; /* first pass: init bodies and parents */ for (i = 0; i < blen; i++) { - s->bodies[i] = malloc(sizeof(Body)); - s->bodies[i]->name = nstrdup(bname[i] + strlen(dir)); + bodies[i] = malloc(sizeof(Body)); + bodies[i]->name = nstrdup(bname[i] + strlen(dir)); bparent[i] = nstrdup(dbget(save->db.systems, bname[i], "parent")); tmp = dbget(save->db.systems, bname[i], "type"); - s->bodies[i]->type = bodytype_enumify(tmp); + bodies[i]->type = bodytype_enumify(tmp); - switch (s->bodies[i]->type) { + switch (bodies[i]->type) { case BODY_STAR: s->num.stars++; break; case BODY_PLANET: s->num.planets++; break; case BODY_DWARF: s->num.dwarfs++; break; @@ -139,48 +139,48 @@ sys_load(System *s, char *name) { case BODY_MOON: s->num.moons++; break; } - s->bodies[i]->radius = strnum(dbget(save->db.systems, bname[i], "radius")); - s->bodies[i]->mass = strnum(dbget(save->db.systems, bname[i], "mass")); - s->bodies[i]->orbdays = strnum(dbget(save->db.systems, bname[i], "orbdays")); - if (s->bodies[i]->type == BODY_COMET) { + bodies[i]->radius = strnum(dbget(save->db.systems, bname[i], "radius")); + bodies[i]->mass = strnum(dbget(save->db.systems, bname[i], "mass")); + bodies[i]->orbdays = strnum(dbget(save->db.systems, bname[i], "orbdays")); + if (bodies[i]->type == BODY_COMET) { /* mindist is on opposite side of parent */ - s->bodies[i]->mindist = 0 - strnum(dbget(save->db.systems, bname[i], "mindist")); - s->bodies[i]->maxdist = strnum(dbget(save->db.systems, bname[i], "maxdist")); - s->bodies[i]->curdist = strnum(dbget(save->db.systems, bname[i], "curdist")); - s->bodies[i]->theta = strnum(dbget(save->db.systems, bname[i], "theta")); - s->bodies[i]->inward = strnum(dbget(save->db.systems, bname[i], "inward")); + bodies[i]->mindist = 0 - strnum(dbget(save->db.systems, bname[i], "mindist")); + bodies[i]->maxdist = strnum(dbget(save->db.systems, bname[i], "maxdist")); + bodies[i]->curdist = strnum(dbget(save->db.systems, bname[i], "curdist")); + bodies[i]->theta = strnum(dbget(save->db.systems, bname[i], "theta")); + bodies[i]->inward = strnum(dbget(save->db.systems, bname[i], "inward")); } else { - s->bodies[i]->dist = strnum(dbget(save->db.systems, bname[i], "dist")); - s->bodies[i]->curtheta = strnum(dbget(save->db.systems, bname[i], "curtheta")); + bodies[i]->dist = strnum(dbget(save->db.systems, bname[i], "dist")); + bodies[i]->curtheta = strnum(dbget(save->db.systems, bname[i], "curtheta")); } /* so sys_get_polar() knows if it's usable */ - s->bodies[i]->polar = (Polar) { INFINITY, INFINITY }; + bodies[i]->polar = (Polar) { INFINITY, INFINITY }; } /* second pass: assign parents (needs bparent[] from first pass) */ for (i = 0; i < blen; i++) { tmp = smprintf("%s%s", dir, bparent[i]); if ((pos = strlistpos(tmp, bname, blen)) != -1) - s->bodies[i]->parent = s->bodies[pos]; + bodies[i]->parent = bodies[pos]; else - s->bodies[i]->parent = NULL; + bodies[i]->parent = NULL; free(tmp); } /* third pass: get coords (needs parent ptr from second pass) */ for (i = 0; i < blen; i++) { - sys_get_polar(s->bodies[i]); /* Builds the cache for us: this is more + sys_get_polar(bodies[i]); /* Builds the cache for us: this is more efficient as it can cache the parent too */ - s->bodies[i]->vector = sys_vectorize(s->bodies[i]->polar); + bodies[i]->vector = sys_vectorize(bodies[i]->polar); /* This could deal with moons, but that's probably not useful. * What about multiple stars in a system? That may need to be * addressed in future */ - if (s->bodies[i]->parent && s->bodies[i]->parent->type == BODY_STAR && (!s->furthest_body || - (s->bodies[i]->type == BODY_COMET ? s->bodies[i]->maxdist : s->bodies[i]->dist) > + if (bodies[i]->parent && bodies[i]->parent->type == BODY_STAR && (!s->furthest_body || + (bodies[i]->type == BODY_COMET ? bodies[i]->maxdist : bodies[i]->dist) > (s->furthest_body->type == BODY_COMET ? s->furthest_body->maxdist : s->furthest_body->dist))) - s->furthest_body = s->bodies[i]; + s->furthest_body = bodies[i]; } for (i = 0; i < blen; i++) { @@ -190,7 +190,14 @@ sys_load(System *s, char *name) { dblistfree(bname, blen); free(dir); - body_sort(s->bodies, s->bodies_len); + body_sort(bodies, blen); + + tree_add_child(&save->systems, s->name, SYSTREE_SYS, s, &s->t); + for (i = 0; i < blen; i++) + tree_add_child(s->t, bodies[i]->name, SYSTREE_BODY, bodies[i], &bodies[i]->t); + + /* The bodies are attached to the systree now, so don't need to be freed */ + free(bodies); return s; } diff --git a/src/tree.c b/src/tree.c @@ -0,0 +1,146 @@ +#include <stdlib.h> +#include "main.h" + +/* This interface is purposely limited to adding children, as opposed to + * appending data on the same level. This is done on purpose, so that ->u + * can always be set. It also means there is always a root Tree structure, + * which does not need to be created with malloc and friends. */ +Tree * +tree_add_child(Tree *t, char *name, int type, void *data, Tree **ptr) { + Tree *p; + Tree *e; + + if (!t) return NULL; + + e = malloc(sizeof(Tree)); + if (!e) return NULL; + + e->p = e->n = e->d = NULL; + e->name = name; + e->type = type; + e->data = data; + e->u = t; + + if (!t->d) { + t->d = e; + } else { + for (p = t->d; p->n; p = p->n); + p->n = e; + e->p = p; + } + + if (ptr) + *ptr = e; + + return e; +} + +/* Deletes a node in the tree and replaces it with its children. */ +int +tree_delete(Tree **t, int freedata) { + Tree *e; + Tree *p; + Tree *fc, *lc; + + if (!*t) + return -1; + + e = *t; + + if (!e->u) + warning("trying to delete root of tree\n"); + + if (e->d) { + fc = e->d; + for (p = fc; p->n; p = p->n); + lc = p; + } else { + fc = lc = NULL; + } + + if (e->p) + e->p->n = fc ? fc : e->n; + else + e->u->d = e->n; + + if (e->n) + e->n->p = lc ? lc : e->p; + + if (freedata) + free(e->data); + free(e); + + return 0; +} + +static Tree * +tree_delete_r_sub(Tree *e, int freedata) { + Tree *c; + Tree *n; + + c = e->d; + n = e->n; + + if (freedata) + free(e->data); + free(e); + + while (c) + c = tree_delete_r_sub(c, freedata); + + return n; +} + +/* Deletes a node and its children. */ +int +tree_delete_r(Tree **t, int freedata) { + Tree *e; + + if (!*t) + return -1; + + e = *t; + + if (!e->u) + warning("trying to delete root of tree\n"); + + if (e->p) + e->p->n = e->n; + else + e->u->d = e->n; + + if (e->n) + e->n->p = e->p; + + tree_delete_r_sub(e, freedata); +} + +int +tree_iter(Tree *t, int maxdepth, Tree **p, int *depth) { + if (!*p) { + *p = t->d; + if (depth) *depth = 0; + return *p ? 0 : -1; + } + + if ((maxdepth < 0 || *depth <= maxdepth) && (*p)->d) { + *p = (*p)->d; + if (depth) (*depth)++; + return 0; + } + + if ((*p)->n) { + *p = (*p)->n; + return 0; + } + + for (; *p && *p != t; *p = (*p)->u) { + if ((*p)->n) { + *p = (*p)->n; + return 0; + } + if (depth) (*depth)--; + } + + return -1; +} diff --git a/src/ui.c b/src/ui.c @@ -503,7 +503,7 @@ ui_draw_view_sys(void) { ui_print(x, y + 40, col_fg, "Comets: %d", view_sys.sel->num.comets); ui_print(x, y + 50, col_fg, "Moons: %d", view_sys.sel->num.moons); ui_draw_line(x, y + 62, x + 85, y + 62, 1, col_fg); - ui_print(x, y + 65, col_fg, "Total: %d", view_sys.sel->bodies_len); + /* ui_print(x, y + 65, col_fg, "Total: %d", view_sys.sel->bodies_len); TODO: tree_count() */ } } diff --git a/src/ui/bodies.c b/src/ui/bodies.c @@ -50,7 +50,9 @@ display_body(Body *body) { void ui_handle_view_bodies(int nowsel) { Vector2 m = GetMousePosition(); - int pos, i, j; + Tree *t; + Body *body; + int pos, i; if (!v->sys) v->sys = sys_default(); @@ -60,10 +62,12 @@ ui_handle_view_bodies(int nowsel) { ui_collides(v->bodies, m)) { pos = (m.y + v->pane.bodies.off - v->bodies.y - PAD) / FONT_SIZE; - for (i = j = 0; i < v->sys->bodies_len && j < pos; i++) - if (display_body(v->sys->bodies[i])) - if (++j == pos) - v->sel = v->sys->bodies[i]; + for (t = v->sys->t->d, i = 0; t && i < pos; t = t->n) { + body = t->data; + if (display_body(body)) + if (++i == pos) + v->sel = body; + } } } @@ -95,7 +99,7 @@ draw_body(int x, int y, Body *body) { void ui_draw_view_bodies(void) { int x, y; - int i; + Tree *t; Body *body; v->stars = RECT(PAD, VIEWS_HEIGHT + PAD * 2 + FONT_SIZE, @@ -123,9 +127,11 @@ ui_draw_view_bodies(void) { y = v->stars.y + PAD/2; ui_print(x, y, col_fg, "Name"); y += FONT_SIZE * 1.5; - for (i = 0; i < v->sys->bodies_len; i++) - if (v->sys->bodies[i]->type == BODY_STAR) - y = draw_star(x, y, v->sys->bodies[i]); + for (t = v->sys->t->d; t; t = t->n) { + body = t->data; + if (body->type == BODY_STAR) + y = draw_star(x, y, body); + } pane_end(); x = v->disp.x + PAD/2; @@ -147,8 +153,8 @@ ui_draw_view_bodies(void) { ui_print(x + 3*W, y, col_fg, "Parent"); ui_print(x + 5*W, y, col_fg, "Type"); y += FONT_SIZE * 1.5; - for (i = 0; i < v->sys->bodies_len; i++) { - body = v->sys->bodies[i]; + for (t = v->sys->t->d; t; t = t->n) { + body = t->data; if (display_body(body)) y = draw_body(x, y, body); } diff --git a/src/ui/main.c b/src/ui/main.c @@ -221,9 +221,9 @@ ui_draw_view_main(void) { Vector2 mousekm = pxtokm(mouse); Vector2 ruler; Geom geom; + Tree *t; Body *body; float dist; - size_t i; float x, y; /* debug info */ @@ -235,13 +235,13 @@ ui_draw_view_main(void) { ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + PAD * 4, col_fg, "FPS: %d (target: %d)", GetFPS(), TARGET_FPS); /* draw system bodies */ - for (i = 0; i < view_main.sys->bodies_len; i++) { - body = view_main.sys->bodies[i]; + for (t = view_main.sys->t->d; t; t = t->n) { + body = t->data; body->pxloc = kmtopx(body->vector); draw_orbit(body); } - for (i = 0; i < view_main.sys->bodies_len; i++) { - body = view_main.sys->bodies[i]; + for (t = view_main.sys->t->d; t; t = t->n) { + body = t->data; draw_body(body); }