From 6066118fc6a58b379f52b9aaaf45200b136812b9 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Mon, 13 Sep 2021 00:09:55 +0300 Subject: [PATCH] tilesets --- src/fs.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/fs.h | 22 +++++++++++++++++ src/game.c | 2 +- src/level.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++---- src/level.h | 23 ++++++++++++++++++ src/scenefile.c | 20 ++++++++++++---- src/scenefile.h | 2 ++ 7 files changed, 199 insertions(+), 9 deletions(-) create mode 100644 src/fs.c create mode 100644 src/fs.h diff --git a/src/fs.c b/src/fs.c new file mode 100644 index 0000000..099e890 --- /dev/null +++ b/src/fs.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include "fs.h" + +char *path_dir(const char *path, char *buf) +{ + char *sep; + + if(!buf) buf = (char*)path; + if(path != buf) { + strcpy(buf, path); + } + + if((sep = strrchr(buf, '/')) && sep > buf) { + *sep = 0; + } + return buf; +} + +char *path_file(const char *path, char *buf) +{ + int len; + char *sep; + + if(!buf) buf = (char*)path; + if(path != buf) { + strcpy(buf, path); + } + + if((sep = strrchr(buf, '/'))) { + len = strlen(sep + 1); + memmove(buf, sep + 1, len + 1); + } + return buf; +} + +char *combine_path(const char *dirname, const char *fname, char *buf) +{ + char *dest; + + if(!buf) return 0; + + if(!dirname || !*dirname) { + strcpy(buf, fname); + return buf; + } + + dest = buf; + while(*dirname) *dest++ = *dirname++; + + if(dest[-1] != '/') *dest++ = '/'; + + strcpy(dest, fname); + return buf; +} + +FILE *fopenat(const char *dirname, const char *fname, const char *attr) +{ + char *buf; + + if(!dirname || !*dirname) { + return fopen(fname, attr); + } + + buf = alloca(strlen(dirname) + strlen(fname) + 2); + combine_path(dirname, fname, buf); + return fopen(buf, attr); +} diff --git a/src/fs.h b/src/fs.h new file mode 100644 index 0000000..752f7b1 --- /dev/null +++ b/src/fs.h @@ -0,0 +1,22 @@ +#ifndef FS_H_ +#define FS_H_ + +#include + +/* buf should be at least as large as strlen(path) + 1 + * if buf is null, or buf points to path, will do in-place replacement + * only UNIX-style path separators are supported + * returns buf + */ +char *path_dir(const char *path, char *buf); +char *path_file(const char *path, char *buf); + +/* buf should be at least strlen(dirname) + strlen(fname) + 2 + * returns buf + */ +char *combine_path(const char *dirname, const char *fname, char *buf); + +/* if dirname is null or empty, this is equivalent to fopen(fname, attr) */ +FILE *fopenat(const char *dirname, const char *fname, const char *attr); + +#endif /* FS_H_ */ diff --git a/src/game.c b/src/game.c index e159ec2..42a95f9 100644 --- a/src/game.c +++ b/src/game.c @@ -68,7 +68,7 @@ void game_display(void) glLoadMatrixf(proj_matrix); cgm_midentity(view_matrix); - cgm_mpretranslate(view_matrix, 0, 0, -cam_dist); + cgm_mpretranslate(view_matrix, 0, 1.5, -cam_dist); cgm_mprerotate(view_matrix, cam_phi, 1, 0, 0); cgm_mprerotate(view_matrix, cam_theta, 0, 1, 0); glMatrixMode(GL_MODELVIEW); diff --git a/src/level.c b/src/level.c index 3a1a9bf..9e5fe44 100644 --- a/src/level.c +++ b/src/level.c @@ -4,6 +4,9 @@ #include #include #include "level.h" +#include "fs.h" + +static int load_tileset(struct level *lvl, struct ts_node *tsn); int init_level(struct level *lvl, int xsz, int ysz) { @@ -20,17 +23,19 @@ void destroy_level(struct level *lvl) { if(!lvl) return; free(lvl->cells); + free(lvl->fname); + free(lvl->dirname); } int load_level(struct level *lvl, const char *fname) { - FILE *fp; struct ts_node *ts, *node, *iter; int sz, cx, cy; struct cell *cell; - if(!(fp = fopen(fname, "rb"))) { - return -1; + lvl->fname = strdup(fname); + if((lvl->dirname = malloc(strlen(fname) + 1))) { + path_dir(lvl->fname, lvl->dirname); } if(!(ts = ts_load(fname))) { @@ -58,7 +63,10 @@ int load_level(struct level *lvl, const char *fname) node = iter; iter = iter->next; - if(strcmp(node->name, "cell") == 0) { + if(strcmp(node->name, "tileset") == 0) { + load_tileset(lvl, node); + + } else if(strcmp(node->name, "cell") == 0) { cx = ts_get_attr_int(node, "x", -1); cy = ts_get_attr_int(node, "y", -1); if(cx < 0 || cy < 0 || cx >= sz || cy >= sz) { @@ -75,6 +83,7 @@ int load_level(struct level *lvl, const char *fname) return 0; } +/* TODO: save tileset info */ int save_level(struct level *lvl, const char *fname) { int i, j; @@ -141,3 +150,56 @@ err: ts_free_tree(root); return -1; } + +static int load_tileset(struct level *lvl, struct ts_node *tsn) +{ + static const char *tile_types[] = {"straight", "corner", "door", 0}; + + int i; + char *path; + const char *str; + struct ts_node *node; + struct tile *tile; + + node = tsn->child_list; + while(node) { + if(strcmp(node->name, "tile") == 0) { + if(!(tile = calloc(1, sizeof *tile))) { + fprintf(stderr, "failed to allocate tile\n"); + return -1; + } + if((str = ts_get_attr_str(node, "name", 0))) { + tile->name = strdup(str); + } + if((str = ts_get_attr_str(node, "type", 0))) { + for(i=0; tile_types[i]; i++) { + if(strcmp(str, tile_types[i]) == 0) { + tile->type = i; + break; + } + } + } + if((str = ts_get_attr_str(node, "scene", 0))) { + if(lvl->dirname) { + path = alloca(strlen(lvl->dirname) + strlen(str) + 2); + combine_path(lvl->dirname, str, path); + } else { + path = (char*)str; + } + load_scenefile(&tile->scn, path); + } + + if(tile->name && tile->scn.meshlist) { /* valid tile */ + tile->next = lvl->tiles; + lvl->tiles = tile; + } else { + fprintf(stderr, "load_tileset: skipping invalid tile: %s\n", + tile->name ? tile->name : "missing tile name"); + free(tile); + } + } + node = node->next; + } + + return 0; +} diff --git a/src/level.h b/src/level.h index 76006f3..6a57dc2 100644 --- a/src/level.h +++ b/src/level.h @@ -1,21 +1,42 @@ #ifndef LEVEL_H_ #define LEVEL_H_ +#include "scenefile.h" + +enum { + TILE_STRAIGHT, + TILE_CORNER, + TILE_DOOR +}; + enum { CELL_SOLID, CELL_WALK, CELL_BLOCKED }; +struct tile { + char *name; + int type; + struct scenefile scn; + struct tile *next; +}; + struct cell { int type; int wall[4]; int floor, ceil; + + struct meshgroup mgrp; }; struct level { + char *fname, *dirname; + int width, height; struct cell *cells; + + struct tile *tiles; }; @@ -25,4 +46,6 @@ void destroy_level(struct level *lvl); int load_level(struct level *lvl, const char *fname); int save_level(struct level *lvl, const char *fname); +int gen_level_geom(struct level *lvl); + #endif /* LEVEL_H_ */ diff --git a/src/scenefile.c b/src/scenefile.c index dda0499..8baf91a 100644 --- a/src/scenefile.c +++ b/src/scenefile.c @@ -61,6 +61,7 @@ int load_scenefile(struct scenefile *scn, const char *fname) char *sep; struct rbtree *rbtree = 0; + memset(scn, 0, sizeof *scn); varr_size = varr_max = narr_size = narr_max = tarr_size = tarr_max = 0; varr = narr = 0; @@ -73,8 +74,7 @@ int load_scenefile(struct scenefile *scn, const char *fname) if(!(rbtree = rb_create(cmp_facevert))) { fprintf(stderr, "load_scenefile: failed to create facevertex search tree\n"); - fclose(fp); - return -1; + goto fail; } rb_set_delete_func(rbtree, free_rbnode_key, 0); @@ -87,6 +87,14 @@ int load_scenefile(struct scenefile *scn, const char *fname) path_prefix = alloca(strlen(buf) + 1); strcpy(path_prefix, buf); + if(sep) { + sep = (char*)fname + (sep - buf); + } + if(!(scn->fname = strdup(sep ? sep + 1 : fname))) { + fprintf(stderr, "failed to allocate scenefile name buffer\n"); + goto fail; + } + if(!(mesh = malloc(sizeof *mesh))) { fprintf(stderr, "failed to allocate mesh\n"); fclose(fp); @@ -199,12 +207,16 @@ int load_scenefile(struct scenefile *scn, const char *fname) } mesh = 0; - printf("load_scenefile: loaded %d meshes, %d vertices\n", scn->num_meshes, - varr_size); + printf("load_scenefile %s: loaded %d meshes, %d vertices\n", scn->fname, + scn->num_meshes, varr_size); res = 0; + if(0) { fail: + free(scn->fname); + } + fclose(fp); free(mesh); free(varr); diff --git a/src/scenefile.h b/src/scenefile.h index 29e9268..745b020 100644 --- a/src/scenefile.h +++ b/src/scenefile.h @@ -4,6 +4,8 @@ #include "mesh.h" struct scenefile { + char *fname; + struct mesh *meshlist; int num_meshes; -- 1.7.10.4