tileset_t* read_tileset(FILE* file) { image_t* atlas = NULL; int atlas_w, atlas_h; long file_pos; int n_tiles_per_row; struct rts_header rts; rect_t segment; struct rts_tile_header tilehdr; struct tile* tiles = NULL; tileset_t* tileset = NULL; int i, j; memset(&rts, 0, sizeof(struct rts_header)); if (file == NULL) goto on_error; file_pos = ftell(file); if ((tileset = calloc(1, sizeof(tileset_t))) == NULL) goto on_error; if (fread(&rts, sizeof(struct rts_header), 1, file) != 1) goto on_error; if (memcmp(rts.signature, ".rts", 4) != 0 || rts.version < 1 || rts.version > 1) goto on_error; if (rts.tile_bpp != 32) goto on_error; if (!(tiles = calloc(rts.num_tiles, sizeof(struct tile)))) goto on_error; // prepare the tile atlas n_tiles_per_row = ceil(sqrt(rts.num_tiles)); atlas_w = rts.tile_width * n_tiles_per_row; atlas_h = rts.tile_height * n_tiles_per_row; if (!(atlas = create_image(atlas_w, atlas_h))) goto on_error; // read in tile bitmaps for (i = 0; i < rts.num_tiles; ++i) { tiles[i].image = read_subimage(file, atlas, i % n_tiles_per_row * rts.tile_width, i / n_tiles_per_row * rts.tile_height, rts.tile_width, rts.tile_height); if (tiles[i].image == NULL) goto on_error; } // read in tile headers and obstruction maps for (i = 0; i < rts.num_tiles; ++i) { if (fread(&tilehdr, sizeof(struct rts_tile_header), 1, file) != 1) goto on_error; tiles[i].name = read_lstring_raw(file, tilehdr.name_length, true); tiles[i].next_index = tilehdr.animated ? tilehdr.next_tile : i; tiles[i].delay = tilehdr.animated ? tilehdr.delay : 0; tiles[i].animate_index = i; tiles[i].frames_left = tiles[i].delay; if (rts.has_obstructions) { switch (tilehdr.obsmap_type) { case 1: // pixel-perfect obstruction (no longer supported) fseek(file, rts.tile_width * rts.tile_height, SEEK_CUR); break; case 2: // line segment-based obstruction tiles[i].num_obs_lines = tilehdr.num_segments; if ((tiles[i].obsmap = new_obsmap()) == NULL) goto on_error; for (j = 0; j < tilehdr.num_segments; ++j) { if (!fread_rect_16(file, &segment)) goto on_error; add_obsmap_line(tiles[i].obsmap, segment); } break; default: goto on_error; } } } // wrap things up free_image(atlas); tileset->width = rts.tile_width; tileset->height = rts.tile_height; tileset->num_tiles = rts.num_tiles; tileset->tiles = tiles; return tileset; on_error: // oh no! if (file != NULL) fseek(file, file_pos, SEEK_SET); if (tiles != NULL) { for (i = 0; i < rts.num_tiles; ++i) { free_lstring(tiles[i].name); free_obsmap(tiles[i].obsmap); free_image(tiles[i].image); } free(tileset->tiles); } free_image(atlas); free(tileset); return NULL; }
tileset_t* tileset_read(sfs_file_t* file) { atlas_t* atlas = NULL; long file_pos; struct rts_header rts; rect_t segment; struct rts_tile_header tilehdr; struct tile* tiles = NULL; tileset_t* tileset = NULL; int i, j; memset(&rts, 0, sizeof(struct rts_header)); console_log(2, "reading tileset #%u from open file", s_next_tileset_id); if (file == NULL) goto on_error; file_pos = sfs_ftell(file); if ((tileset = calloc(1, sizeof(tileset_t))) == NULL) goto on_error; if (sfs_fread(&rts, sizeof(struct rts_header), 1, file) != 1) goto on_error; if (memcmp(rts.signature, ".rts", 4) != 0 || rts.version < 1 || rts.version > 1) goto on_error; if (rts.tile_bpp != 32) goto on_error; if (!(tiles = calloc(rts.num_tiles, sizeof(struct tile)))) goto on_error; // read in all the tile bitmaps (use atlasing) if (!(atlas = atlas_new(rts.num_tiles, rts.tile_width, rts.tile_height))) goto on_error; atlas_lock(atlas); for (i = 0; i < rts.num_tiles; ++i) if (!(tiles[i].image = atlas_load(atlas, file, i, rts.tile_width, rts.tile_height))) goto on_error; atlas_unlock(atlas); tileset->atlas = atlas; // read in tile headers and obstruction maps for (i = 0; i < rts.num_tiles; ++i) { if (sfs_fread(&tilehdr, sizeof(struct rts_tile_header), 1, file) != 1) goto on_error; tiles[i].name = read_lstring_raw(file, tilehdr.name_length, true); tiles[i].next_index = tilehdr.animated ? tilehdr.next_tile : i; tiles[i].delay = tilehdr.animated ? tilehdr.delay : 0; tiles[i].image_index = i; tiles[i].frames_left = tiles[i].delay; if (rts.has_obstructions) { switch (tilehdr.obsmap_type) { case 1: // pixel-perfect obstruction (no longer supported) sfs_fseek(file, rts.tile_width * rts.tile_height, SFS_SEEK_CUR); break; case 2: // line segment-based obstruction tiles[i].num_obs_lines = tilehdr.num_segments; if ((tiles[i].obsmap = obsmap_new()) == NULL) goto on_error; for (j = 0; j < tilehdr.num_segments; ++j) { if (!fread_rect_16(file, &segment)) goto on_error; obsmap_add_line(tiles[i].obsmap, segment); } break; default: goto on_error; } } } // wrap things up tileset->id = s_next_tileset_id++; tileset->width = rts.tile_width; tileset->height = rts.tile_height; tileset->num_tiles = rts.num_tiles; tileset->tiles = tiles; return tileset; on_error: // oh no! console_log(2, "failed to read tileset #%u", s_next_tileset_id); if (file != NULL) sfs_fseek(file, file_pos, SFS_SEEK_SET); if (tiles != NULL) { for (i = 0; i < rts.num_tiles; ++i) { lstr_free(tiles[i].name); obsmap_free(tiles[i].obsmap); free_image(tiles[i].image); } free(tileset->tiles); } atlas_free(atlas); free(tileset); return NULL; }