almost done with the level reorganization
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 25 Sep 2021 06:04:39 +0000 (09:04 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 25 Sep 2021 06:04:39 +0000 (09:04 +0300)
src/game.c
src/level.c
src/level.h
src/scenefile.c
src/scenefile.h
src/tileset.c
src/tileset.h

index 3194196..2007694 100644 (file)
@@ -44,7 +44,6 @@ int game_init(void)
        if(load_level(&lvl, "data/test.lvl") == -1) {
                return -1;
        }
-       gen_level_geom(&lvl);
 
        init_player(&player);
        player.lvl = &lvl;
@@ -152,6 +151,15 @@ static void draw_level(void)
                        glPushMatrix();
                        glMultMatrixf(xform);
 
+                       if(cell->tile) {
+                               cgm_mrotation_y(xform, cell->tilerot * M_PI / 2.0f);
+
+                               glPushMatrix();
+                               glMultMatrixf(xform);
+                               draw_meshgroup(&cell->tile->mgrp);
+                               glPopMatrix();
+                       }
+
                        for(k=0; k<cell->num_mgrp; k++) {
                                draw_meshgroup(cell->mgrp + k);
                        }
index fcf2556..6867e64 100644 (file)
@@ -7,6 +7,9 @@
 #include "tileset.h"
 #include "fs.h"
 
+static int detect_cell_tile(struct level *lvl, int x, int y, int *rot);
+
+
 int init_level(struct level *lvl, int xsz, int ysz)
 {
        memset(lvl, 0, sizeof *lvl);
@@ -33,9 +36,10 @@ void destroy_level(struct level *lvl)
 int load_level(struct level *lvl, const char *fname)
 {
        struct ts_node *ts, *node, *iter;
-       int i, j, sz, cx, cy;
+       int i, j, sz, cx, cy, tiletype;
        struct cell *cell;
        float *vecptr;
+       const char *str;
 
        if(!(ts = ts_load(fname))) {
                fprintf(stderr, "failed to load level: %s\n", fname);
@@ -71,15 +75,16 @@ int load_level(struct level *lvl, const char *fname)
                lvl->py = vecptr[1];
        }
 
+       if((str = ts_get_attr_str(ts, "tileset", 0))) {
+               lvl->tset = get_tileset(str);
+       }
+
        iter = ts->child_list;
        while(iter) {
                node = iter;
                iter = iter->next;
 
-               if(strcmp(node->name, "tileset") == 0) {
-                       /* TODO */
-
-               } else if(strcmp(node->name, "cell") == 0) {
+               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) {
@@ -94,7 +99,6 @@ int load_level(struct level *lvl, const char *fname)
                }
        }
 
-       /* assign wall types to all occupied cells */
        cell = lvl->cells;
        for(i=0; i<lvl->height; i++) {
                for(j=0; j<lvl->width; j++) {
@@ -103,25 +107,15 @@ int load_level(struct level *lvl, const char *fname)
                                continue;
                        }
 
-                       /* TODO take wall choice from the level file into account */
-                       /* TODO detect corners */
                        node = (struct ts_node*)cell->next;
                        cell->next = 0;
 
-                       /*
-                       if(i >= lvl->height - 1 || cell[lvl->width].type == CELL_SOLID) {
-                               cell->wall[0] = TILE_STR;
+                       if((tiletype = tile_type(ts_get_attr_str(node, "tiletype", 0))) == -1) {
+                               /* no tile-type specified, try to guess */
+                               tiletype = detect_cell_tile(lvl, j, i, &cell->tilerot);
                        }
-                       if(j >= lvl->width - 1 || cell[1].type == CELL_SOLID) {
-                               cell->wall[1] = TILE_STR;
-                       }
-                       if(i <= 0 || cell[-lvl->width].type == CELL_SOLID) {
-                               cell->wall[2] = TILE_STR;
-                       }
-                       if(j <= 0 || cell[-1].type == CELL_SOLID) {
-                               cell->wall[3] = TILE_STR;
-                       }
-                       */
+
+                       cell->tile = get_tile(lvl->tset, tiletype);
 
                        cell++;
                }
@@ -215,81 +209,104 @@ err:
 
 #ifndef LEVEL_EDITOR
 
-int gen_cell_geom(struct level *lvl, struct cell *cell)
+static int get_cell_type(struct level *lvl, int x, int y)
 {
-#if 0
-       int i;
-       struct meshgroup *wallgeom;
-       struct tile *tstr;
-       struct mesh *mesh, *tmesh;
-       float xform[16];
-
-       if(!(tstr = find_level_tile(lvl, TILE_STR))) {
-               return -1;
+       if(x < 0 || x >= lvl->width || y < 0 || y >= lvl->height) {
+               return CELL_SOLID;
        }
-
-       if(!(wallgeom = malloc(sizeof *wallgeom))) {
-               return -1;
-       }
-       init_meshgroup(wallgeom);
-
-       for(i=0; i<4; i++) {
-               if(cell->wall[i] == TILE_STR) { /* TODO: support other wall types */
-                       cgm_mrotation_y(xform, i * M_PI / 2.0f);
-
-                       tmesh = tstr->scn.meshlist;
-                       while(tmesh) {
-                               if(!(mesh = malloc(sizeof *mesh))) {
-                                       return -1;
-                               }
-
-                               /* create a copy of the tile mesh */
-                               if(copy_mesh(mesh, tmesh) == -1) {
-                                       free(mesh);
-                                       return -1;
-                               }
-                               if(i) xform_mesh(mesh, xform);  /* rotate it to match the wall angle */
-
-                               /* add it to the level meshlist */
-                               mesh->next = lvl->meshlist;
-                               lvl->meshlist = mesh;
-
-                               /* add it to the meshgroup */
-                               if(add_meshgroup_mesh(wallgeom, mesh) == -1) {
-                                       destroy_mesh(mesh);
-                                       free(mesh);
-                                       return -1;
-                               }
-
-                               tmesh = tmesh->next;
-                       }
-               }
-       }
-
-       /* TODO: append to other existing meshgroups for detail objects */
-       cell->mgrp = wallgeom;
-       cell->num_mgrp = 1;
-#endif
-       return 0;
+       return lvl->cells[y * lvl->width + x].type;
 }
 
-int gen_level_geom(struct level *lvl)
+static int detect_cell_tile(struct level *lvl, int x, int y, int *rot)
 {
-       int i, j;
-       struct cell *cell;
-
-       for(i=0; i<lvl->height; i++) {
-               for(j=0; j<lvl->width; j++) {
-                       cell = lvl->cells + i * lvl->width + j;
-                       if(cell->type != CELL_SOLID) {
-                               if(gen_cell_geom(lvl, cell) == -1) {
-                                       printf("failed to generate cell\n");
-                                       return -1;
-                               }
+       int i, j, bit;
+       unsigned int adj = 0;
+
+       bit = 0;
+       for(i=0; i<3; i++) {
+               for(j=0; j<3; j++) {
+                       if(i == 1 && j == 1) continue;
+                       if(get_cell_type(lvl, x + j - 1, y + i - 1) == CELL_SOLID) {
+                               adj |= 1 << bit;
                        }
+                       bit++;
                }
        }
-       return 0;
+
+       *rot = 0;
+
+       switch(adj) {
+       case 0:
+       case 0757:
+               /* really we'd need a separate tile type for "all neighbors solid", but we
+                * probably never going to need that in practice, so fuck it.
+                */
+               return TILE_OPEN;
+
+       case 0555:      /* N-S corridor */
+               *rot = 1;
+       case 0707:      /* W-E corridor */
+               return TILE_STR;
+
+       case 0745:      /* S-E corner */
+               *rot = 1;
+       case 0715:      /* S-W corner */
+               return TILE_CORNER;
+       case 0547:      /* N-E corner */
+               *rot = 2;
+               return TILE_CORNER;
+       case 0517:      /* N-W corner */
+               *rot = 3;
+               return TILE_CORNER;
+
+       case 0507:      /* N tee */
+               *rot = 3;
+       case 0515:      /* W tee */
+               return TILE_TEE;
+       case 0705:      /* S tee */
+               *rot = 1;
+               return TILE_TEE;
+       case 0545:      /* E tee */
+               *rot = 2;
+               return TILE_TEE;
+
+       case 0505:      /* cross */
+               return TILE_CROSS;
+
+       case 0700:      /* S stropen */
+       case 0701:
+       case 0704:
+               return TILE_STROPEN;
+       case 0444:      /* E stropen */
+       case 0445:
+       case 0544:
+               *rot = 1;
+               return TILE_STROPEN;
+       case 0007:      /* N stropen */
+       case 0407:
+       case 0107:
+               *rot = 2;
+               return TILE_STROPEN;
+       case 0111:      /* W stropen */
+       case 0511:
+       case 0115:
+               *rot = 3;
+               return TILE_STROPEN;
+
+       case 0404:      /* E str2open */
+               return TILE_STR2OPEN;
+       case 0005:      /* N str2open */
+               *rot = 1;
+               return TILE_STR2OPEN;
+       case 0101:      /* W str2open */
+               *rot = 2;
+               return TILE_STR2OPEN;
+       case 0500:      /* S str2open */
+               *rot = 3;
+               return TILE_STR2OPEN;
+       }
+
+       return TILE_OPEN;
 }
 
 #endif /* !LEVEL_EDITOR */
index 6e6eed7..d1e9931 100644 (file)
@@ -12,7 +12,8 @@ enum {
        TILE_CORNER,
        TILE_TEE,
        TILE_CROSS,
-       TILE_STR2OPEN
+       TILE_STR2OPEN,
+       TILE_STROPEN
 };
 
 enum {
@@ -24,14 +25,19 @@ enum {
 struct tile {
        char *name;
        int type;
+
+       struct meshgroup mgrp;
+
        struct tile *next;
 };
 
 struct cell {
        int type;
+       int tiletype, tilerot;
        int wall[4];
        int floor, ceil;
 
+       struct tile *tile;
        struct meshgroup *mgrp;
        int num_mgrp;
 
index 25cdf28..92cdb1f 100644 (file)
@@ -273,19 +273,6 @@ void destroy_scenefile(struct scenefile *scn)
        }
 }
 
-struct mesh *find_mesh_prefix(struct scenefile *scn, const char *prefix)
-{
-       int len = strlen(prefix);
-       struct mesh *m = scn->meshlist;
-       while(m) {
-               if(m->name && memcmp(m->name, prefix, len) == 0) {
-                       return m;
-               }
-               m = m->next;
-       }
-       return 0;
-}
-
 static char *cleanline(char *s)
 {
        char *ptr;
index ab59b6a..745b020 100644 (file)
@@ -16,6 +16,4 @@ struct scenefile {
 int load_scenefile(struct scenefile *scn, const char *fname);
 void destroy_scenefile(struct scenefile *scn);
 
-struct mesh *find_mesh_prefix(struct scenefile *scn, const char *prefix);
-
 #endif /* SCENEFILE_H_ */
index cde3021..240b17f 100644 (file)
@@ -7,12 +7,19 @@
 #include "level.h"
 #include "fs.h"
 
+static int match_prefix(const char *str, const char *prefix);
+
+static struct tileset *tset_list;
+
 int load_tileset(struct tileset *tset, const char *fname)
 {
        struct ts_node *ts, *node, *iter;
        const char *str;
        char *path;
        struct mesh *mesh;
+       struct tile *tile;
+       int type;
+       float xform[16], *vec;
 
        if(!(ts = ts_load(fname))) {
                fprintf(stderr, "failed to load tileset: %s\n", fname);
@@ -39,6 +46,7 @@ int load_tileset(struct tileset *tset, const char *fname)
                return -1;
        }
 
+       tset->fname = strdup(fname);
        tset->name = strdup(ts_get_attr_str(ts, "name", fname));
 
        iter = ts->child_list;
@@ -49,13 +57,129 @@ int load_tileset(struct tileset *tset, const char *fname)
                        if(!(str = ts_get_attr_str(node, "prefix", 0))) {
                                continue;
                        }
-                       if(!(mesh = find_mesh_prefix(&tset->scn, str))) {
-                               fprintf(stderr, "load_tileset: failed to find mesh with prefix: %s\n", str);
+
+                       if((type = tile_type(ts_get_attr_str(node, "type", 0))) == -1) {
+                               fprintf(stderr, "load_tileset: missing or invalid tile type\n");
                                continue;
                        }
-                       /* TOOD cont */
+
+                       if(!(tile = malloc(sizeof *tile))) {
+                               fprintf(stderr, "load_tileset: failed to allocate tile\n");
+                               continue;
+                       }
+                       tile->type = type;
+
+                       cgm_midentity(xform);
+                       if((vec = ts_get_attr_vec(node, "pos", 0))) {
+                               cgm_mtranslation(xform, vec[0], vec[1], vec[2]);
+                       }
+
+                       init_meshgroup(&tile->mgrp);
+
+                       mesh = tset->scn.meshlist;
+                       while(mesh) {
+                               if(match_prefix(mesh->name, str)) {
+                                       if(vec) {
+                                               xform_mesh(mesh, xform);
+                                       }
+                                       add_meshgroup_mesh(&tile->mgrp, mesh);
+                               }
+                               mesh = mesh->next;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+void destroy_tileset(struct tileset *tset)
+{
+       struct tile *tile;
+
+       free(tset->name);
+       free(tset->fname);
+
+       while(tset->tiles) {
+               tile = tset->tiles;
+               tset->tiles = tile->next;
+
+               free(tile->name);
+               free(tile);
+       }
+
+       destroy_scenefile(&tset->scn);
+}
+
+struct tileset *get_tileset(const char *fname)
+{
+       struct tileset *ts = tset_list;
+       while(ts) {
+               if(strcmp(ts->fname, fname) == 0) {
+                       return ts;
                }
+               ts = ts->next;
+       }
+
+       if(!(ts = malloc(sizeof *ts))) {
+               fprintf(stderr, "failed to allocate tileset\n");
+               return 0;
+       }
+       if(load_tileset(ts, fname) == -1) {
+               free(ts);
+               return 0;
        }
+       ts->next = tset_list;
+       tset_list = ts;
+       return ts;
+}
+
+void free_all_tilesets(void)
+{
+       struct tileset *ts;
 
+       while(tset_list) {
+               ts = tset_list;
+               tset_list = ts->next;
+               destroy_tileset(ts);
+               free(ts);
+       }
+}
+
+struct tile *get_tile(struct tileset *tset, int ttype)
+{
+       struct tile *tile = tset->tiles;
+       while(tile) {
+               if(tile->type == ttype) {
+                       return tile;
+               }
+               tile = tile->next;
+       }
        return 0;
 }
+
+int tile_type(const char *tstr)
+{
+       static const char *typenames[] = {
+               "open", "straight", "corner", "tee", "cross", "str2open", "stropen", 0
+       };
+       int i;
+
+       if(!tstr) return -1;
+
+       for(i=0; typenames[i]; i++) {
+               if(strcmp(tstr, typenames[i]) == 0) {
+                       return i;
+               }
+       }
+       return -1;
+}
+
+static int match_prefix(const char *str, const char *prefix)
+{
+       while(*str && *prefix) {
+               if(*str++ != *prefix++) {
+                       return 0;
+               }
+       }
+       return 1;
+}
index 82d4ec3..8d4634c 100644 (file)
@@ -6,15 +6,22 @@
 struct tile;
 
 struct tileset {
-       const char *name;
+       char *name, *fname;
 
        struct scenefile scn;   /* scene file containing tile geometry */
        struct tile *tiles;
+
+       struct tileset *next;
 };
 
 int load_tileset(struct tileset *tset, const char *fname);
 void destroy_tileset(struct tileset *tset);
 
-struct tileset *get_tileset(const char *name);
+struct tileset *get_tileset(const char *fname);
+void free_all_tilesets(void);
+
+struct tile *get_tile(struct tileset *tset, int ttype);
+
+int tile_type(const char *tstr);
 
 #endif /* TILESET_H_ */