tilesets
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sun, 12 Sep 2021 21:09:55 +0000 (00:09 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sun, 12 Sep 2021 21:09:55 +0000 (00:09 +0300)
src/fs.c [new file with mode: 0644]
src/fs.h [new file with mode: 0644]
src/game.c
src/level.c
src/level.h
src/scenefile.c
src/scenefile.h

diff --git a/src/fs.c b/src/fs.c
new file mode 100644 (file)
index 0000000..099e890
--- /dev/null
+++ b/src/fs.c
@@ -0,0 +1,69 @@
+#include <stdio.h>
+#include <string.h>
+#include <alloca.h>
+#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 (file)
index 0000000..752f7b1
--- /dev/null
+++ b/src/fs.h
@@ -0,0 +1,22 @@
+#ifndef FS_H_
+#define FS_H_
+
+#include <stdio.h>
+
+/* 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_ */
index e159ec2..42a95f9 100644 (file)
@@ -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);
index 3a1a9bf..9e5fe44 100644 (file)
@@ -4,6 +4,9 @@
 #include <errno.h>
 #include <treestore.h>
 #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;
+}
index 76006f3..6a57dc2 100644 (file)
@@ -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_ */
index dda0499..8baf91a 100644 (file)
@@ -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);
index 29e9268..745b020 100644 (file)
@@ -4,6 +4,8 @@
 #include "mesh.h"
 
 struct scenefile {
+       char *fname;
+
        struct mesh *meshlist;
        int num_meshes;