Esempio n. 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;
}
Esempio n. 2
0
font_t*
load_font(const char* filename)
{
	image_t*                atlas = NULL;
	int                     atlas_x, atlas_y;
	int                     atlas_size_x, atlas_size_y;
	sfs_file_t*             file;
	font_t*                 font = NULL;
	struct font_glyph*      glyph;
	struct rfn_glyph_header glyph_hdr;
	long                    glyph_start;
	uint8_t*                grayscale;
	image_lock_t*           lock = NULL;
	int                     max_x = 0, max_y = 0;
	int                     min_width = INT_MAX;
	int64_t                 n_glyphs_per_row;
	int                     pixel_size;
	struct rfn_header       rfn;
	uint8_t                 *psrc;
	color_t                 *pdest;

	int i, x, y;
	
	console_log(2, "loading font #%u as `%s`", s_next_font_id, filename);
	
	memset(&rfn, 0, sizeof(struct rfn_header));

	if ((file = sfs_fopen(g_fs, filename, NULL, "rb")) == NULL) goto on_error;
	if (!(font = calloc(1, sizeof(font_t)))) goto on_error;
	if (sfs_fread(&rfn, sizeof(struct rfn_header), 1, file) != 1)
		goto on_error;
	pixel_size = (rfn.version == 1) ? 1 : 4;
	if (!(font->glyphs = calloc(rfn.num_chars, sizeof(struct font_glyph))))
		goto on_error;

	// pass 1: load glyph headers and find largest glyph
	glyph_start = sfs_ftell(file);
	for (i = 0; i < rfn.num_chars; ++i) {
		glyph = &font->glyphs[i];
		if (sfs_fread(&glyph_hdr, sizeof(struct rfn_glyph_header), 1, file) != 1)
			goto on_error;
		sfs_fseek(file, glyph_hdr.width * glyph_hdr.height * pixel_size, SFS_SEEK_CUR);
		max_x = fmax(glyph_hdr.width, max_x);
		max_y = fmax(glyph_hdr.height, max_y);
		min_width = fmin(min_width, glyph_hdr.width);
		glyph->width = glyph_hdr.width;
		glyph->height = glyph_hdr.height;
	}
	font->num_glyphs = rfn.num_chars;
	font->min_width = min_width;
	font->max_width = max_x;
	font->height = max_y;

	// create glyph atlas
	n_glyphs_per_row = ceil(sqrt(rfn.num_chars));
	atlas_size_x = max_x * n_glyphs_per_row;
	atlas_size_y = max_y * n_glyphs_per_row;
	if ((atlas = create_image(atlas_size_x, atlas_size_y)) == NULL)
		goto on_error;

	// pass 2: load glyph data
	sfs_fseek(file, glyph_start, SFS_SEEK_SET);
	if (!(lock = lock_image(atlas))) goto on_error;
	for (i = 0; i < rfn.num_chars; ++i) {
		glyph = &font->glyphs[i];
		if (sfs_fread(&glyph_hdr, sizeof(struct rfn_glyph_header), 1, file) != 1)
			goto on_error;
		atlas_x = i % n_glyphs_per_row * max_x;
		atlas_y = i / n_glyphs_per_row * max_y;
		switch (rfn.version) {
		case 1: // RFN v1: 8-bit grayscale glyphs
			if (!(glyph->image = create_subimage(atlas, atlas_x, atlas_y, glyph_hdr.width, glyph_hdr.height)))
				goto on_error;
			grayscale = malloc(glyph_hdr.width * glyph_hdr.height);
			if (sfs_fread(grayscale, glyph_hdr.width * glyph_hdr.height, 1, file) != 1)
				goto on_error;
			psrc = grayscale;
			pdest = lock->pixels + atlas_x + atlas_y * lock->pitch;
			for (y = 0; y < glyph_hdr.height; ++y) {
				for (x = 0; x < glyph_hdr.width; ++x)
					pdest[x] = color_new(psrc[x], psrc[x], psrc[x], 255);
				pdest += lock->pitch;
				psrc += glyph_hdr.width;
			}
			break;
		case 2: // RFN v2: 32-bit truecolor glyphs
			if (!(glyph->image = read_subimage(file, atlas, atlas_x, atlas_y, glyph_hdr.width, glyph_hdr.height)))
				goto on_error;
			break;
		}
	}
	unlock_image(atlas, lock);
	sfs_fclose(file);
	free_image(atlas);
	
	font->id = s_next_font_id++;
	return ref_font(font);

on_error:
	console_log(2, "failed to load font #%u", s_next_font_id++);
	sfs_fclose(file);
	if (font != NULL) {
		for (i = 0; i < rfn.num_chars; ++i) {
			if (font->glyphs[i].image != NULL) free_image(font->glyphs[i].image);
		}
		free(font->glyphs);
		free(font);
	}
	if (lock != NULL) unlock_image(atlas, lock);
	if (atlas != NULL) free_image(atlas);
	return NULL;
}