From 6a120e64b1c3092d8929292882641d376ad0993b Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Sat, 25 Sep 2021 09:04:39 +0300 Subject: [PATCH] almost done with the level reorganization --- src/game.c | 10 ++- src/level.c | 193 ++++++++++++++++++++++++++++++------------------------- src/level.h | 8 ++- src/scenefile.c | 13 ---- src/scenefile.h | 2 - src/tileset.c | 130 ++++++++++++++++++++++++++++++++++++- src/tileset.h | 11 +++- 7 files changed, 257 insertions(+), 110 deletions(-) diff --git a/src/game.c b/src/game.c index 3194196..2007694 100644 --- a/src/game.c +++ b/src/game.c @@ -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; knum_mgrp; k++) { draw_meshgroup(cell->mgrp + k); } diff --git a/src/level.c b/src/level.c index fcf2556..6867e64 100644 --- a/src/level.c +++ b/src/level.c @@ -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; iheight; i++) { for(j=0; jwidth; 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; iheight; i++) { - for(j=0; jwidth; 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 */ diff --git a/src/level.h b/src/level.h index 6e6eed7..d1e9931 100644 --- a/src/level.h +++ b/src/level.h @@ -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; diff --git a/src/scenefile.c b/src/scenefile.c index 25cdf28..92cdb1f 100644 --- a/src/scenefile.c +++ b/src/scenefile.c @@ -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; diff --git a/src/scenefile.h b/src/scenefile.h index ab59b6a..745b020 100644 --- a/src/scenefile.h +++ b/src/scenefile.h @@ -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_ */ diff --git a/src/tileset.c b/src/tileset.c index cde3021..240b17f 100644 --- a/src/tileset.c +++ b/src/tileset.c @@ -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; +} diff --git a/src/tileset.h b/src/tileset.h index 82d4ec3..8d4634c 100644 --- a/src/tileset.h +++ b/src/tileset.h @@ -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_ */ -- 1.7.10.4