Ejemplo n.º 1
0
Archivo: font.c Proyecto: dmalves/cage
int load_font(struct font* font, const char* filepath, int ncols, int nrows)
{
    uint32_t* pixels = NULL;
    int pitch = 0;
    uint32_t bg_color;
    int cell_w, cell_h, top, base_a, curr_char;
    int rows;
    int i;

    if (init_image_from_file(&font->image, filepath) == -1) return -1;
    if ((font->image.width / ncols) * (font->image.height / nrows) >
        MAX_FONT_CHARS)
        return -1;
    if (lock_image(&font->image, (void**)&pixels, &pitch) == -1) return -1;

    bg_color = pixels[0];

    cell_w = font->image.width / ncols;
    cell_h = font->image.height / nrows;

    top = cell_h;
    base_a = cell_h;

    curr_char = 0;

    for (rows = 0; rows < nrows; ++rows) {
        int cols;
        for (cols = 0; cols < ncols; ++cols) {
            int p_col, p_row;
            font->chars_rects[curr_char].x = cell_w * cols;
            font->chars_rects[curr_char].y = cell_h * rows;

            font->chars_rects[curr_char].w = cell_w;
            font->chars_rects[curr_char].h = cell_h;

            for (p_col = 0; p_col < cell_w; ++p_col) {
                for (p_row = 0; p_row < cell_h; ++p_row) {
                    int px = (cell_w * cols) + p_col;
                    int py = (cell_h * rows) + p_row;

                    if (get_pixel32(pixels, pitch, px, py) != bg_color) {
                        font->chars_rects[curr_char].x = px;
                        p_col = cell_w;
                        p_row = cell_h;
                    }
                }
            }

            for (p_col = cell_w - 1; p_col >= 0; --p_col) {
                for (p_row = 0; p_row < cell_h; ++p_row) {
                    int px = (cell_w * cols) + p_col;
                    int py = (cell_h * rows) + p_row;

                    if (get_pixel32(pixels, pitch, px, py) != bg_color) {
                        font->chars_rects[curr_char].w =
                        (px - font->chars_rects[curr_char].x) + 1;
                        p_col = -1;
                        p_row = cell_h;
                    }
                }
            }

            for (p_row = 0; p_row < cell_h; ++p_row) {
                for (p_col = 0; p_col < cell_w; ++p_col) {
                    int px = (cell_w * cols) + p_col;
                    int py = (cell_h * rows) + p_row;

                    if (get_pixel32(pixels, pitch, px, py) != bg_color) {
                        if (p_row < top) {
                            top = p_row;
                        }
                        /* Break the loops */
                        p_col = cell_w;
                        p_row = cell_h;
                    }
                }
            }

            if (curr_char == 'A') {
                for (p_row = cell_h - 1; p_row >= 0; --p_row) {
                    for (p_col = 0; p_col < cell_w; ++p_col) {
                        int px = (cell_w * cols) + p_col;
                        int py = (cell_h * rows) + p_row;

                        if (get_pixel32(pixels, pitch, px, py) != bg_color) {
                            base_a = p_row;
                            p_col = cell_w;
                            p_row = -1;
                        }
                    }
                }
            }

            ++curr_char;
        }
    }

    font->space_width = cell_w / 2;
    font->line_height = base_a - top + 2;
    font->char_spacing = 0;
    font->line_spacing = 0;

    for (i = 0; i < ncols * nrows; ++i) {
        font->chars_rects[i].y += top;
        font->chars_rects[i].h -= top;
    }

    unlock_image(&font->image);
    return 0;
}
Ejemplo 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;
}