Example #1
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;
}
Example #2
0
File: filter.c Project: Azizou/XaoS
/* An function helping to filter create new image.
 * It should be called by filter in inicialization. Filter passes
 * width,height,pixelwidth, pixelheight
 * and palette he wants to pass to his child and flags defining how it works
 * with image(IMAGEDATA if it requires data from previous frames (like blur
 * filter, TOUCHIMAGE if it changes data in image(like blur or stereogram
 * filter but unlike interlace and NEWIMAGE if it strictly requires to create
 * new image)
 * As palette he should pass NULL to keep parents palette. Same as
 * (pixel)width/height should be passed 0;
 *
 * Function then aplies some heruistic in order to minimize memory
 * requirements. So it should share image, create image that shares image data
 * or create new image)
 *
 * fills f->image, f->childimage and returns 1 if sucess and 0 if fail(usually
 * out of memory or it is unable to fit child's requirements)
 * and prepares data for child call.
 */
int
inherimage(struct filter *f, struct initdata *data, int flags, int width,
	   int height, struct palette *palette, float pixelwidth,
	   float pixelheight)
{
    int newimage = 0;
    int subimage = 1;
    int sharedimage = 1;
    struct image *i;

    int ddatalost = 0;
    if (width == 0)
	width = data->image->width;
    if (height == 0)
	height = data->image->height;
#ifdef DEBUG
    printf("Inherimage:%s %i %i imagedata:%i %i\n", f->name, width, height,
	   flags & IMAGEDATA, flags & PROTECTBUFFERS);
#endif
    if (pixelwidth == 0)
	pixelwidth = data->image->pixelwidth;
    if (pixelheight == 0)
	pixelheight = data->image->pixelheight;
    if (palette == NULL)
	palette = data->image->palette;
    if (!(palette->type & f->req.supportedmask)) {
#ifdef DEBUG
	printf
	    ("Initalization of filter %s failed due to unsupported type by child %s-%i,%i\n",
	     f->name, f->previous->name, f->req.supportedmask,
	     palette->type);
#endif
	f->image = data->image;
	return 0;
    }

    if (flags & NEWIMAGE)
	newimage = 1, sharedimage = 0, subimage = 0;
    if ((flags & IMAGEDATA) /*|| (data->image->flags & PROTECTBUFFERS) */ )
	subimage = 0, sharedimage = 0, newimage = 1;
    /*if filter touches data but child requires them, create separated image */
    if ((flags & TOUCHIMAGE)
	&& ((f->req.flags & IMAGEDATA)
	    || (data->image->flags & PROTECTBUFFERS)))
	subimage = 0, newimage = 1, sharedimage = 0;
    /*if required image differs in size or so */
    if (width != data->image->width || height != data->image->height ||
	palette != data->image->palette)
	newimage = 1, sharedimage = 0;

    if (f->childimage != NULL && (f->flags & ALLOCEDIMAGE)) {
	/*is an old child image still useable for us purposes? if not burn it it! */
	/*We should share image? Why alloc new?? */
	if (!newimage && (f->flags & ALLOCEDIMAGE))
	    destroyinheredimage(f), ddatalost = 1;
	/*We should share data? but child image dont do that! */
	if (subimage && !(f->flags & SHAREDDATA))
	    destroyinheredimage(f), ddatalost = 1;
	/*We can't share data but child image does that? */
	if (!subimage && (f->flags & SHAREDDATA))
	    destroyinheredimage(f), ddatalost = 1;
	/*When image changed, child image must be recreated too */
	if (f->flags & SHAREDDATA && ((data->flags & DATALOST)
				      || f->imageversion !=
				      data->image->version))
	    destroyinheredimage(f), ddatalost = 1;
	/*We should share image with filter? Why keep created new one? */
	if (sharedimage)
	    destroyinheredimage(f), ddatalost = 1;
	/*When child image don't fit out needs */
	if (f->childimage != NULL
	    && (f->childimage->width != width
		|| f->childimage->height != height
		|| f->childimage->palette != palette
		|| f->childimage->bytesperpixel !=
		bytesperpixel(palette->type)
		|| f->childimage->nimages < f->req.nimages))
	    destroyinheredimage(f), ddatalost = 1;
	/*Well now child image seems to be heavily probed */
    }
    i = f->childimage;
    if (newimage) {		/*Create new image when required */
	if (!(f->flags & ALLOCEDIMAGE)) {
	    if (subimage) {
		i = create_subimage(data->image, width, height,
				    f->req.nimages, palette, pixelwidth,
				    pixelheight);
		f->flags |= ALLOCEDIMAGE | SHAREDDATA;
		ddatalost = 1;
	    } else {
		i = create_image_mem(width, height, f->req.nimages,
				     palette, pixelwidth, pixelheight);
		f->flags |= ALLOCEDIMAGE;
		ddatalost = 1;
	    }
	}
    }
#ifdef DEBUG
    printf("Filter:%s newimage:%i subimage:%i sharedimage:%i\n", f->name,
	   newimage, subimage, sharedimage);
#endif
    if (i == NULL) {
	f->image = data->image;
	return 0;
    }
    if (sharedimage)
	i = data->image, ddatalost = (data->flags & DATALOST)
	    || (f->childimage != data->image);
    if (sharedimage && datalost(f, data))
	ddatalost = 1;
    else if ((f->flags | SHAREDDATA) && datalost(f, data)
	     && !(i->flags & FREEDATA))
	ddatalost = 1;
    if (ddatalost)
	data->flags |= DATALOST;
    else
	data->flags &= ~DATALOST;
    f->image = data->image;
    f->childimage = i;
    f->imageversion = data->image->version;
    data->image = i;
#ifdef DEBUG
    printf("OK %i datalost:%i\n", f->flags, ddatalost);
#endif
#ifdef DEBUG
    printf("Inherimage2:%s %i %i\n", f->name, width, height);
#endif
    return 1;
}
Example #3
0
font_t*
load_font(const char* path)
{
	image_t*                atlas = NULL;
	int                     atlas_size_x, atlas_size_y;
	ALLEGRO_LOCKED_REGION*  bitmap_lock;
	FILE*                   file;
	font_t*                 font = NULL;
	struct font_glyph*      glyph;
	struct rfn_glyph_header glyph_hdr;
	long                    glyph_start;
	int                     max_x = 0, max_y = 0;
	int                     min_width = INT_MAX;
	int64_t                 n_glyphs_per_row;
	size_t                  pixel_size;
	struct rfn_header       rfn;
	uint8_t                 *src_ptr, *dest_ptr;

	int i, x, y;

	memset(&rfn, 0, sizeof(struct rfn_header));

	if ((file = fopen(path, "rb")) == NULL) goto on_error;
	if (!(font = calloc(1, sizeof(font_t)))) goto on_error;
	if (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 = ftell(file);
	for (i = 0; i < rfn.num_chars; ++i) {
		glyph = &font->glyphs[i];
		if (fread(&glyph_hdr, sizeof(struct rfn_glyph_header), 1, file) != 1)
			goto on_error;
		fseek(file, glyph_hdr.width * glyph_hdr.height * pixel_size, 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->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
	fseek(file, glyph_start, SEEK_SET);
	for (i = 0; i < rfn.num_chars; ++i) {
		glyph = &font->glyphs[i];
		if (fread(&glyph_hdr, sizeof(struct rfn_glyph_header), 1, file) != 1)
			goto on_error;
		size_t data_size = glyph_hdr.width * glyph_hdr.height * pixel_size;
		void* data = malloc(data_size);
		if (fread(data, 1, data_size, file) != data_size) goto on_error;
		glyph->image = create_subimage(atlas,
			i % n_glyphs_per_row * max_x, i / n_glyphs_per_row * max_y,
			glyph_hdr.width, glyph_hdr.height);
		if (glyph->image == NULL) goto on_error;
		if ((bitmap_lock = al_lock_bitmap(get_image_bitmap(glyph->image), ALLEGRO_PIXEL_FORMAT_ABGR_8888, ALLEGRO_LOCK_WRITEONLY)) == NULL)
			goto on_error;
		src_ptr = data; dest_ptr = bitmap_lock->data;
		switch (rfn.version) {
		case 1: // RFN v1: 8-bit grayscale glyphs
			for (y = 0; y < glyph_hdr.height; ++y) {
				for (x = 0; x < glyph_hdr.width; ++x) {
					dest_ptr[x] = src_ptr[x];
					dest_ptr[x + 1] = src_ptr[x];
					dest_ptr[x + 2] = src_ptr[x];
					dest_ptr[x + 3] = 255;
					dest_ptr += 4;
				}
				dest_ptr += bitmap_lock->pitch - (glyph_hdr.width * 4);
				src_ptr += glyph_hdr.width;
			}
			break;
		case 2: // RFN v2: 32-bit truecolor glyphs
			for (y = 0; y < glyph_hdr.height; ++y) {
				memcpy(dest_ptr, src_ptr, glyph_hdr.width * 4);
				dest_ptr += bitmap_lock->pitch;
				src_ptr += glyph_hdr.width * pixel_size;
			}
			break;
		}
		al_unlock_bitmap(get_image_bitmap(glyph->image));
		free(data);
	}
	fclose(file);
	free_image(atlas);
	return ref_font(font);

on_error:
	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 (atlas != NULL) free_image(atlas);
	return NULL;
}