#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H

int ft_error_code;
#define FT_ASSERT(a)	ft_error_code = a; do if ( ft_error_code ) { printf("FreeType2 Error: %s  [Code = %d]\n", #a, ft_error_code); exit(1); } while ( 0 )
#define TH 63

struct METRICS {
	int w, h;
	int bx, by;
	int adv;
	
	int index;
	FT_Glyph glyph;
};

struct RECT {
	int x1,x2,y1,y2;
} r;

unsigned char*
	ft2_get_string_pic(
	FT_Face face,
	int * str,
	int	len)
{
	FT_BitmapGlyph glyph_bitmap;
	int c;
	struct METRICS *metrics;
	int w, h, ws, hs;
	int x0, x_st, hang;
	int i, x, y, y1, y2, y_st;
	unsigned char *src, *dst;
	int *kerning;
	int size = 160;
	unsigned char *ret;
	
	if ( face == 0 ) {
		return 0;
	}
	
	FT_ASSERT( FT_Set_Char_Size(face, 0, size*64/10, 72, 72) );
	metrics = (struct METRICS*)malloc(sizeof(struct METRICS) * len);
	w = h = 0;
	y1 = y2 = 0;
	for ( i = 0 ; i < len ; i++ ) {
		c = str[i];
		metrics[i].index = FT_Get_Char_Index(face, c);
		if ( metrics[i].index ) {
			printf("metrics[%d].index = %d\t", i, metrics[i].index);
			FT_ASSERT( FT_Load_Glyph(face, metrics[i].index, FT_LOAD_DEFAULT) );
			FT_ASSERT( FT_Get_Glyph(face->glyph, &metrics[i].glyph) );
		if ( metrics[i].glyph->format != ft_glyph_format_bitmap )
				FT_ASSERT( FT_Glyph_To_Bitmap(&metrics[i].glyph, ft_render_mode_normal, 0, 1) );
			metrics[i].w = (face->glyph->metrics.width+TH) >> 6;
			metrics[i].h = (face->glyph->metrics.height+TH) >> 6;
			metrics[i].bx = (face->glyph->metrics.horiBearingX+TH) >> 6;
			metrics[i].by = (face->glyph->metrics.horiBearingY+TH) >> 6;
			metrics[i].adv = (face->glyph->metrics.horiAdvance+TH) >> 6;
			printf("%dx%d %d-%d %d\n", metrics[i].w, metrics[i].h, metrics[i].bx, metrics[i].by, metrics[i].adv);
			w += metrics[i].adv;
			if ( y1 > -metrics[i].by )
				y1 = -metrics[i].by;
			if ( y2 < metrics[i].h - metrics[i].by )
				y2 = metrics[i].h - metrics[i].by;
			if ( i > 0 && FT_HAS_KERNING(face) ) {
				FT_Vector delta;
				FT_Get_Kerning(face, metrics[i-1].index, metrics[i].index, 0, &delta);
				metrics[i].adv -= delta.x >> 6;
				w -= delta.x >> 6;
			}
		}
	}
	
	x0 = 0;
	if ( metrics[0].bx < 0 ) {
		w -= metrics[0].bx;
		x0 = - metrics[0].bx;
	}
	hang = metrics[len-1].bx + metrics[len-1].w;
	if ( hang > metrics[len-1].adv )
		w += hang - metrics[len-1].adv;
	h = y2 - y1;
	if ( h == 0 ) {
		y1--;
		h++;
	}
	
	r.x1 = 0;
	r.x2 = w;
	r.y1 = y1;
	r.y2 = y2;
	printf("%d\n", w);
	
	if ( w )
		ret = malloc(w*h);
	else
		ret = 0;
	for ( i = 0 ; i < w*h ; i++ )
		ret[i] = 255;
	
	for ( i = 0 ; i < len ; i++ ) {
		if ( metrics[i].index ) {
			glyph_bitmap = (FT_BitmapGlyph)metrics[i].glyph;
			src = glyph_bitmap->bitmap.buffer;
			ws = glyph_bitmap->bitmap.width;
			hs = glyph_bitmap->bitmap.rows;
			x_st = metrics[i].bx;
			y_st = -y1-metrics[i].by;
			
			for ( y = 0 ; y < hs ; y++ ) {
				printf("%5d ", x0+x_st + (y_st+y)*w);
				dst = &ret[x0+x_st + (y_st+y)*w];
				for ( x = 0 ; x < ws ; x++ ) {
					*dst = (((int)*dst+1)*(256-(int)*src)>>8)-1;
					printf(*dst<180?"[]":"  ");
					src++;
					dst++;
				}
				printf("\n");
			}
			x0 += metrics[i].adv;
			
			FT_Done_Glyph(metrics[i].glyph);
		}
	}
	
	free(metrics);
	ret[0] = 0x87;
	return ret;
}

int
main(int argc, char* argv[])
{
	FT_Library library;
	FT_Face face;
	FT_GlyphSlot slot;
	int glyph_index;
	int char_code = 'c';
	int x, y, w, h, len = 2;
	int str[] = {0x4e0b, 0x308a};
	unsigned char *buffer;
	
	if ( argc < 2 ) {
		fprintf(stderr, "usage %s <font file>\n", argv[0]);
		exit(1);
	}
	FT_ASSERT( FT_Init_FreeType(&library) );
	FT_ASSERT( FT_New_Face(library,
		argv[1],
		0,
		&face) );
	printf("includes %d faces\n", face->num_faces);
	
	FT_ASSERT( FT_Set_Char_Size(
		face,    /* handle to face object           */
		0,       /* char_width in 1/64th of points  */
		12*64,   /* char_height in 1/64th of points */
		72,     /* horizontal device resolution    */
		72) );   /* vertical device resolution      */
	
	
	printf("char_code   : %x\n", char_code);
	glyph_index = FT_Get_Char_Index(face, char_code);
	printf("glyph_index : %x\n", glyph_index);
	FT_ASSERT( FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) );
	slot = face->glyph;
	FT_ASSERT( FT_Render_Glyph(slot, ft_render_mode_normal) );
	printf("pos  : %d x %d\n", slot->bitmap_left, slot->bitmap_top);
	w = slot->bitmap.width;
	h = slot->bitmap.rows;
	printf("size : %d x %d\n", w, h);
	printf("advance : %d\n", slot->advance.x>>6);
	if ( FT_HAS_KERNING(face) ) {
		printf("karning info :\n");
		FT_Vector  delta;
		FT_Get_Kerning(face, 'A', glyph_index, 0, &delta);
		printf("    delta for 'A' : %d\n", delta.x >> 6);
		FT_Get_Kerning(face, 'V', glyph_index, 0, &delta);
		printf("    delta for 'V' : %d\n", delta.x >> 6);
	}
	printf("\n");
	
	buffer = ft2_get_string_pic(face, str, len);
	printf("%p %x\n", buffer, buffer[0]);
	w = r.x2-r.x1;
	for ( y = 0 ; y < r.y2-r.y1 ; y++ ) {
		//for ( x = 0 ; x < r.x2-r.x1 ; x++ )
		//	printf("%3d ", buffer[x+w*y]);
		//printf("   ");
		for ( x = 0 ; x < w ; x++ )
			printf(buffer[x+w*y] < 180? "[]" : "  ");
		printf("\n");
	}
	
	printf("size : %d x %d - %d\n", w, r.y1, r.y2);
	return 0;
}