# HG changeset patch # User David Demelier # Date 1585593000 -7200 # Node ID c7e9934559859382c35760299d044c4f50208dcb # Parent 58133933ea17e72ad1dfce3a172a8be469f31419 map: split the map structure into two definitions While here, add some macros to increase map_state readability. diff -r 58133933ea17 -r c7e993455985 src/adventure/mainmenu_state.c --- a/src/adventure/mainmenu_state.c Mon Mar 30 20:10:00 2020 +0200 +++ b/src/adventure/mainmenu_state.c Mon Mar 30 20:30:00 2020 +0200 @@ -89,8 +89,12 @@ static void new(void) { + /* TODO: convenient map_state_start function? */ + /* Prepare map. */ - if (!map_open(&map_state_data.map.map, sys_datapath("maps/test.map"))) + if (!map_data_open(&map_state_data.map.data, sys_datapath("maps/test.map"))) + panic(); + if (!map_init(&map_state_data.map.map, &map_state_data.map.data)) panic(); /* Prepare image and sprite. */ diff -r 58133933ea17 -r c7e993455985 src/adventure/panic_state.c --- a/src/adventure/panic_state.c Mon Mar 30 20:10:00 2020 +0200 +++ b/src/adventure/panic_state.c Mon Mar 30 20:30:00 2020 +0200 @@ -95,8 +95,8 @@ fprintf(fp, "Molko's Adventure crash dump report\n"); fprintf(fp, "== state map dump ==\n"); fprintf(fp, "map:\n"); - fprintf(fp, " w %u\n", map_state_data.map.w); - fprintf(fp, " h %u\n", map_state_data.map.h); + fprintf(fp, " w %u\n", map_state_data.map.data.w); + fprintf(fp, " h %u\n", map_state_data.map.data.h); fprintf(fp, "player:\n"); fprintf(fp, " x: %u\n", map_state_data.player.x); fprintf(fp, " y: %u\n", map_state_data.player.y); diff -r 58133933ea17 -r c7e993455985 src/core/map.c --- a/src/core/map.c Mon Mar 30 20:10:00 2020 +0200 +++ b/src/core/map.c Mon Mar 30 20:30:00 2020 +0200 @@ -31,14 +31,12 @@ #include "texture.h" #include "window.h" -#include - /* Create %c string literal for scanf */ #define MAX_F(v) MAX_F_(v) #define MAX_F_(v) "%" #v "c" static void -parse_layer(struct map *map, const char *line, FILE *fp) +parse_layer(struct map_data *data, const char *line, FILE *fp) { char layer_name[32 + 1] = { 0 }; struct map_layer *layer; @@ -48,17 +46,17 @@ if (sscanf(line, "layer|%32s", layer_name) <= 0) return; if (strcmp(layer_name, "background") == 0) - layer = &map->layers[0]; + layer = &data->layers[0]; else if (strcmp(layer_name, "foreground") == 0) - layer = &map->layers[1]; + layer = &data->layers[1]; else return; /* Check if weight/height has been specified. */ - if (map->width == 0 || map->height == 0) + if (data->w == 0 || data->h == 0) return; - amount = map->width * map->height; + amount = data->w * data->h; current = 0; if (!(layer->tiles = calloc(amount, sizeof (unsigned short)))) @@ -69,51 +67,36 @@ } static void -parse_tileset(struct map *map, const char *line) -{ - char filename[128 + 1] = { 0 }; - - sscanf(line, "tileset|%128s", filename); - - if (map->tilewidth == 0 || map->tileheight == 0) - return; - if (!(image_open(&map->tileset, sys_datapath("tilesets/%s", filename)))) - return; -} - -static void -parse(struct map *map, const char *line, FILE *fp) +parse(struct map_data *data, const char *line, FILE *fp) { if (strncmp(line, "title", 5) == 0) - sscanf(line, "title|" MAX_F(MAP_TITLE_MAX), map->title); + sscanf(line, "title|" MAX_F(MAP_TITLE_MAX), data->title); else if (strncmp(line, "width", 5) == 0) - sscanf(line, "width|%u", &map->width); + sscanf(line, "width|%u", &data->w); else if (strncmp(line, "height", 6) == 0) - sscanf(line, "height|%u", &map->height); + sscanf(line, "height|%u", &data->h); else if (strncmp(line, "tilewidth", 9) == 0) - sscanf(line, "tilewidth|%hu", &map->tilewidth); + sscanf(line, "tilewidth|%hu", &data->tile_w); else if (strncmp(line, "tileheight", 10) == 0) - sscanf(line, "tileheight|%hu", &map->tileheight); + sscanf(line, "tileheight|%hu", &data->tile_h); else if (strncmp(line, "origin", 6) == 0) - sscanf(line, "origin|%d|%d", &map->origin_x, &map->origin_y); + sscanf(line, "origin|%d|%d", &data->origin_x, &data->origin_y); else if (strncmp(line, "tileset", 7) == 0) - parse_tileset(map, line); + sscanf(line, "tileset|" MAX_F(MAP_TILESET_MAX), data->tileset); else if (strncmp(line, "layer", 5) == 0) - parse_layer(map, line, fp); + parse_layer(data, line, fp); } static bool -check(struct map *map) +check(struct map_data *data) { - if (strlen(map->title) == 0) - return error_printf("map has no title"); - if (!map->tileset.w || !map->tileset.h) - return error_printf("unable to open tileset"); - if (map->width == 0 || map->height == 0) - return error_printf("map has null sizes"); - if (map->tilewidth == 0 || map->tileheight == 0) - return error_printf("map has null tile sizes"); - if (!map->layers[0].tiles || !map->layers[1].tiles) + if (strlen(data->title) == 0) + return error_printf("data has no title"); + if (data->w == 0 || data->h == 0) + return error_printf("data has null sizes"); + if (data->tile_w == 0 || data->tile_h == 0) + return error_printf("data has null tile sizes"); + if (!data->layers[0].tiles || !data->layers[1].tiles) return error_printf("could not allocate data"); return true; @@ -128,32 +111,32 @@ struct sprite sprite; int x = 0, y = 0; - sprite_init(&sprite, &map->tileset, map->tilewidth, map->tileheight); + sprite_init(&sprite, &map->tileset, map->data->tile_w, map->data->tile_h); - for (unsigned int r = 0; r < map->width; ++r) { - for (unsigned int c = 0; c < map->height; ++c) { - unsigned int si = r * map->width + c; + for (unsigned int r = 0; r < map->data->w; ++r) { + for (unsigned int c = 0; c < map->data->h; ++c) { + unsigned int si = r * map->data->w + c; unsigned int sr = (layer->tiles[si] - 1) / sprite.ncols; unsigned int sc = (layer->tiles[si] - 1) % sprite.nrows; if (layer->tiles[si] != 0) sprite_draw(&sprite, sr, sc, x, y); - x += map->tilewidth; + x += map->data->tile_w; } x = 0; - y += map->tileheight; + y += map->data->tile_h; } } bool -map_open(struct map *map, const char *path) +map_data_open(struct map_data *data, const char *path) { - assert(map); + assert(data); assert(path); - memset(map, 0, sizeof (struct map)); + memset(data, 0, sizeof (*data)); FILE *fp = fopen(path, "r"); char line[BUFSIZ]; @@ -164,48 +147,69 @@ while (fgets(line, sizeof (line), fp)) { /* Remove \n if any */ line[strcspn(line, "\n")] = '\0'; - parse(map, line, fp); + parse(data, line, fp); } fclose(fp); - if (!check(map)) { - map_finish(map); + if (!check(data)) { + map_data_finish(data); return false; } - size_t pw = map->width * map->tilewidth; - size_t ph = map->height * map->tileheight; - - if (!(texture_new(&map->picture, pw, ph))) - return error_sdl(); + /* Compute real size. */ + data->real_w = data->w * data->tile_w; + data->real_h = data->h * data->tile_h; return true; } void +map_data_finish(struct map_data *data) +{ + assert(data); + + free(data->layers[0].tiles); + free(data->layers[1].tiles); + + memset(data, 0, sizeof (*data)); +} + +bool +map_init(struct map *map, struct map_data *data) +{ + assert(map); + assert(data); + + if (!(image_open(&map->tileset, sys_datapath("tilesets/%s", data->tileset)))) + goto failure; + if (!(texture_new(&map->picture, data->real_w, data->real_h))) + goto failure; + + map->data = data; + map_repaint(map); + + return true; + +failure: + map_data_finish(data); + + return false; +} + +void map_draw(struct map *map, int srcx, int srcy) { - texture_scale( - &map->picture, - srcx, - srcy, - window.w, - window.h, - 0, - 0, - window.w, - window.h, - 0 - ); + texture_scale(&map->picture, srcx, srcy, window.w, window.h, + 0, 0, window.w, window.h, 0.0); } void map_repaint(struct map *map) { PAINTER_BEGIN(&map->picture); - draw_layer(map, &map->layers[0]); - draw_layer(map, &map->layers[1]); + draw_layer(map, &map->data->layers[0]); + draw_layer(map, &map->data->layers[1]); PAINTER_END(); } @@ -217,8 +221,5 @@ texture_finish(&map->tileset); texture_finish(&map->picture); - free(map->layers[0].tiles); - free(map->layers[1].tiles); - - memset(map, 0, sizeof (struct map)); + memset(map, 0, sizeof (*map)); } diff -r 58133933ea17 -r c7e993455985 src/core/map.h --- a/src/core/map.h Mon Mar 30 20:10:00 2020 +0200 +++ b/src/core/map.h Mon Mar 30 20:30:00 2020 +0200 @@ -25,6 +25,7 @@ */ #include +#include #include "texture.h" @@ -34,6 +35,11 @@ #define MAP_TITLE_MAX 32 /** + * \brief Max filename for tilesets. + */ +#define MAP_TILESET_MAX FILENAME_MAX + +/** * \brief Map layer. */ struct map_layer { @@ -41,35 +47,68 @@ }; /** - * \brief Map object. + * \brief Map definition structure. * * This structure only defines the map characteristics. It does not have any * logic and is left for game state. */ +struct map_data { + char title[MAP_TITLE_MAX]; /*!< (RW) The map title. */ + char tileset[MAP_TILESET_MAX]; /*!< (RO) Name of tileset to use. */ + int origin_x; /*!< (RO) Where the player starts in X. */ + int origin_y; /*!< (RO) Where the player starts in Y. */ + unsigned int real_w; /*!< (RO) Real width in pixels. */ + unsigned int real_h; /*!< (RO) Real height in pixels. */ + unsigned int w; /*!< (RO) Map width in cells. */ + unsigned int h; /*!< (RO) Map height in cells. */ + unsigned short tile_w; /*!< (RO) Pixels per cell (width). */ + unsigned short tile_h; /*!< (RO) Pixels per cell (height). */ + struct map_layer layers[2]; /*!< (RO) Layers (background, foreground). */ +}; + +/** + * \brief High level map object. + * + * This structure reference a map and perform drawing operations. + */ struct map { - char title[MAP_TITLE_MAX]; /*!< (RW) The map title */ - struct texture tileset; /*!< (RW) Tileset to use */ - struct texture picture; /*!< (RO) Map drawn into a picture */ - int origin_x; /*!< (RO) Where the player starts in X */ - int origin_y; /*!< (RO) Where the player starts in Y */ - unsigned int width; /*!< (RO) Map width in cells */ - unsigned int height; /*!< (RO) Map height in cells */ - unsigned short tilewidth; /*!< (RO) Pixels per cell (width) */ - unsigned short tileheight; /*!< (RO) Pixels per cell (height) */ - struct map_layer layers[2]; /*!< (RO) Layers (background, foreground) */ + struct map_data *data; /*!< (RW, ref) Map data. */ + struct texture tileset; /*!< (RW) Tileset to use. */ + struct texture picture; /*!< (RO) Map drawn into a picture. */ }; /** - * Open a map. + * Open a map defintion + * + * \pre data != NULL + * \pre path != NULL + * \param data the map defintion to fill + * \param path the path to the map + * \return True if successfully loaded. + */ +bool +map_data_open(struct map_data *data, const char *path); + +/** + * Dispose the map definition data. + * + * \pre data != NULL + * \param data the map definition + */ +void +map_data_finish(struct map_data *data); + +/** + * Initialize this map. * * \pre map != NULL - * \pre path != NULL - * \param map the map to fill - * \param path the path to the map - * \return true if successfully loaded + * \pre data != NULL + * \param map the map to initialize + * \param data the definition to reference + * \return False on errors. */ bool -map_open(struct map *map, const char *path); +map_init(struct map *map, struct map_data *data); /** * Render a map. @@ -87,16 +126,16 @@ * * \pre map != NULL * \param map the map to repaint - * \warning This function does not render anything on the screen + * \warning This function does not render anything on the screen. */ void map_repaint(struct map *map); /** - * Close the map and its resources. + * Dispose map resources. * * \pre map != NULL - * \param map the map to render + * \param map the map to close */ void map_finish(struct map *map); diff -r 58133933ea17 -r c7e993455985 src/core/map_state.c --- a/src/core/map_state.c Mon Mar 30 20:10:00 2020 +0200 +++ b/src/core/map_state.c Mon Mar 30 20:30:00 2020 +0200 @@ -46,6 +46,13 @@ #define MARGIN_HEIGHT 80 /* + * Convenient macros to access the state data. + */ +#define MAP() (&map_state_data.map) +#define PLAYER() (&map_state_data.player) +#define VIEW() (&map_state_data.view) + +/* * This structure defines the possible movement of the player as flags since * it's possible to make diagonal movements. */ @@ -102,18 +109,18 @@ static void center(void) { - map_state_data.view.x = map_state_data.player.x - (map_state_data.view.w / 2); - map_state_data.view.y = map_state_data.player.y - (map_state_data.view.h / 2); + VIEW()->x = PLAYER()->x - (VIEW()->w / 2); + VIEW()->y = PLAYER()->y - (VIEW()->h / 2); - if (map_state_data.view.x < 0) - map_state_data.view.x = 0; - else if ((unsigned int)map_state_data.view.x > map_state_data.map.w - map_state_data.view.w) - map_state_data.view.x = map_state_data.map.w - map_state_data.view.w; + if (VIEW()->x < 0) + VIEW()->x = 0; + else if ((unsigned int)VIEW()->x > MAP()->data.real_w - VIEW()->w) + VIEW()->x = MAP()->data.real_w - VIEW()->w; - if (map_state_data.view.y < 0) - map_state_data.view.y = 0; - else if ((unsigned int)map_state_data.view.y > map_state_data.map.h - map_state_data.view.h) - map_state_data.view.y = map_state_data.map.h - map_state_data.view.h; + if (VIEW()->y < 0) + VIEW()->y = 0; + else if ((unsigned int)VIEW()->y > MAP()->data.real_h - VIEW()->h) + VIEW()->y = MAP()->data.real_h - VIEW()->h; } static void @@ -123,22 +130,22 @@ struct map *m = &map_state_data.map.map; map_repaint(m); - map_state_data.map.w = m->picture.w; - map_state_data.map.h = m->picture.h; + MAP()->data.real_w = m->picture.w; + MAP()->data.real_h = m->picture.h; /* Adjust view. */ - map_state_data.view.w = window.w; - map_state_data.view.h = window.h; + VIEW()->w = window.w; + VIEW()->h = window.h; /* Adjust margin. */ - cache.margin.w = map_state_data.view.w - (MARGIN_WIDTH * 2); - cache.margin.h = map_state_data.view.h - (MARGIN_HEIGHT * 2); + cache.margin.w = VIEW()->w - (MARGIN_WIDTH * 2); + cache.margin.h = VIEW()->h - (MARGIN_HEIGHT * 2); /* Center the view by default. */ center(); /* Final bits. */ - walksprite_init(&cache.player.ws, &map_state_data.player.sprite, 300); + walksprite_init(&cache.player.ws, &PLAYER()->sprite, 300); } static void @@ -166,7 +173,7 @@ break; } - map_state_data.player.angle = orientations[cache.player.moving]; + PLAYER()->angle = orientations[cache.player.moving]; } static void @@ -193,65 +200,65 @@ static void move_right(unsigned int delta) { - map_state_data.player.x += delta; + PLAYER()->x += delta; - if (map_state_data.player.x > (int)(cache.margin.x + cache.margin.w)) { - map_state_data.view.x = (map_state_data.player.x - map_state_data.view.w) + MARGIN_WIDTH; + if (PLAYER()->x > (int)(cache.margin.x + cache.margin.w)) { + VIEW()->x = (PLAYER()->x - VIEW()->w) + MARGIN_WIDTH; - if (map_state_data.view.x >= (int)(map_state_data.map.w - map_state_data.view.w)) - map_state_data.view.x = map_state_data.map.w - map_state_data.view.w; + if (VIEW()->x >= (int)(MAP()->data.real_w - VIEW()->w)) + VIEW()->x = MAP()->data.real_w - VIEW()->w; } - if (map_state_data.player.x > (int)map_state_data.map.w - 48) - map_state_data.player.x = map_state_data.map.w - 48; + if (PLAYER()->x > (int)MAP()->data.real_w - 48) + PLAYER()->x = MAP()->data.real_w - 48; } static void move_left(unsigned int delta) { - map_state_data.player.x -= delta; + PLAYER()->x -= delta; - if (map_state_data.player.x < cache.margin.x) { - map_state_data.view.x = map_state_data.player.x - MARGIN_WIDTH; + if (PLAYER()->x < cache.margin.x) { + VIEW()->x = PLAYER()->x - MARGIN_WIDTH; - if (map_state_data.view.x < 0) - map_state_data.view.x = 0; + if (VIEW()->x < 0) + VIEW()->x = 0; } - if (map_state_data.player.x < 0) - map_state_data.player.x = 0; + if (PLAYER()->x < 0) + PLAYER()->x = 0; } static void move_down(unsigned int delta) { - map_state_data.player.y += delta; + PLAYER()->y += delta; - if (map_state_data.player.y > (int)(cache.margin.y + cache.margin.h)) { - map_state_data.view.y = (map_state_data.player.y - map_state_data.view.h) + MARGIN_HEIGHT; + if (PLAYER()->y > (int)(cache.margin.y + cache.margin.h)) { + VIEW()->y = (PLAYER()->y - VIEW()->h) + MARGIN_HEIGHT; - if (map_state_data.view.y >= (int)(map_state_data.map.h - map_state_data.view.h)) - map_state_data.view.y = map_state_data.map.h - map_state_data.view.h; + if (VIEW()->y >= (int)(MAP()->data.real_h - VIEW()->h)) + VIEW()->y = MAP()->data.real_h - VIEW()->h; } - if (map_state_data.player.y > (int)map_state_data.map.h - 48) - map_state_data.player.y = map_state_data.map.h - 48; + if (PLAYER()->y > (int)MAP()->data.real_h - 48) + PLAYER()->y = MAP()->data.real_h - 48; } static void move_up(unsigned int delta) { - map_state_data.player.y -= delta; + PLAYER()->y -= delta; - if (map_state_data.player.y < cache.margin.y) { - map_state_data.view.y = map_state_data.player.y - MARGIN_HEIGHT; + if (PLAYER()->y < cache.margin.y) { + VIEW()->y = PLAYER()->y - MARGIN_HEIGHT; - if (map_state_data.view.y < 0) - map_state_data.view.y = 0; + if (VIEW()->y < 0) + VIEW()->y = 0; } - if (map_state_data.player.y < 0) - map_state_data.player.y = 0; + if (PLAYER()->y < 0) + PLAYER()->y = 0; } static void @@ -261,8 +268,8 @@ const int delta = SPEED * ticks / SEC; /* This is the rectangle within the view where users must be. */ - cache.margin.x = map_state_data.view.x + MARGIN_WIDTH; - cache.margin.y = map_state_data.view.y + MARGIN_HEIGHT; + cache.margin.x = VIEW()->x + MARGIN_WIDTH; + cache.margin.y = VIEW()->y + MARGIN_HEIGHT; int dx = 0; int dy = 0; @@ -319,17 +326,17 @@ { struct debug_report report = DEBUG_INIT_DEFAULTS; - map_draw(&map_state_data.map.map, map_state_data.view.x, map_state_data.view.y); + map_draw(&map_state_data.map.map, VIEW()->x, VIEW()->y); walksprite_draw( &cache.player.ws, - map_state_data.player.angle, - map_state_data.player.x - map_state_data.view.x, - map_state_data.player.y - map_state_data.view.y); + PLAYER()->angle, + PLAYER()->x - VIEW()->x, + PLAYER()->y - VIEW()->y); - debug_printf(&report, "position: %d, %d", map_state_data.player.x, - map_state_data.player.y); - debug_printf(&report, "view: %d, %d", map_state_data.view.x, - map_state_data.view.y); + debug_printf(&report, "position: %d, %d", PLAYER()->x, + PLAYER()->y); + debug_printf(&report, "view: %d, %d", VIEW()->x, + VIEW()->y); } struct map_state_data map_state_data; diff -r 58133933ea17 -r c7e993455985 src/core/map_state.h --- a/src/core/map_state.h Mon Mar 30 20:10:00 2020 +0200 +++ b/src/core/map_state.h Mon Mar 30 20:30:00 2020 +0200 @@ -38,9 +38,8 @@ * Map properties. */ struct { - struct map map; /*!< (RW) The map definition */ - unsigned int w; /*!< (RO) Map width */ - unsigned int h; /*!< (RO) Map height */ + struct map_data data; /*!< (RW) Map data. */ + struct map map; /*!< (RW) Map object. */ } map; /** diff -r 58133933ea17 -r c7e993455985 tests/test-map.c --- a/tests/test-map.c Mon Mar 30 20:10:00 2020 +0200 +++ b/tests/test-map.c Mon Mar 30 20:30:00 2020 +0200 @@ -24,37 +24,17 @@ #include #include -static void -setup(void *data) -{ - (void)data; - - if (!sys_init()) - panic(); - if (!window_init("Test map", 100, 100)) - panic(); -} - -static void -teardown(void *data) -{ - (void)data; - - window_finish(); - sys_finish(); -} - TEST sample(void) { - struct map map; + struct map_data map; - ASSERT(map_open(&map, sys_datapath("maps/sample-map.map"))); + ASSERT(map_data_open(&map, sys_datapath("maps/sample-map.map"))); ASSERT_STR_EQ("This is a test map", map.title); - ASSERT_EQ(2, map.width); - ASSERT_EQ(2, map.height); - ASSERT_EQ(32, map.tilewidth); - ASSERT_EQ(16, map.tileheight); + ASSERT_EQ(2, map.w); + ASSERT_EQ(2, map.h); + ASSERT_EQ(32, map.tile_w); + ASSERT_EQ(16, map.tile_h); ASSERT_EQ(0, map.layers[0].tiles[0]); ASSERT_EQ(1, map.layers[0].tiles[1]); ASSERT_EQ(2, map.layers[0].tiles[2]); @@ -69,59 +49,55 @@ TEST error_title(void) { - struct map map; + struct map_data map; - ASSERT(!map_open(&map, sys_datapath("maps/error-title.map"))); + ASSERT(!map_data_open(&map, sys_datapath("maps/error-title.map"))); PASS(); } TEST error_width(void) { - struct map map; + struct map_data map; - ASSERT(!map_open(&map, sys_datapath("maps/error-width.map"))); + ASSERT(!map_data_open(&map, sys_datapath("maps/error-width.map"))); PASS(); } TEST error_height(void) { - struct map map; + struct map_data map; - ASSERT(!map_open(&map, sys_datapath("maps/error-height.map"))); + ASSERT(!map_data_open(&map, sys_datapath("maps/error-height.map"))); PASS(); } TEST error_tilewidth(void) { - struct map map; + struct map_data map; - ASSERT(!map_open(&map, sys_datapath("maps/error-tilewidth.map"))); + ASSERT(!map_data_open(&map, sys_datapath("maps/error-tilewidth.map"))); PASS(); } TEST error_tileheight(void) { - struct map map; + struct map_data map; - ASSERT(!map_open(&map, sys_datapath("maps/error-tileheight.map"))); + ASSERT(!map_data_open(&map, sys_datapath("maps/error-tileheight.map"))); PASS(); } SUITE(basics) { - SET_SETUP(setup, NULL); - SET_TEARDOWN(teardown, NULL); RUN_TEST(sample); } SUITE(errors) { - SET_SETUP(setup, NULL); - SET_TEARDOWN(teardown, NULL); RUN_TEST(error_title); RUN_TEST(error_width); RUN_TEST(error_height);