예제 #1
0
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;
}
예제 #2
0
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;
}