#define STB_TRUETYPE_IMPLEMENTATION
#include "stb_truetype.h"
#include "dat.h"
#include "fn.h"

typedef struct Glyph Glyph;
struct Glyph
{
	uchar *bmp;
	int w, h, ox, oy, adv;
};

enum { Maxfonts = 4 };

static stbtt_fontinfo fonts[Maxfonts];
static uchar *fontdata[Maxfonts];
static float scale[Maxfonts];
static int nfonts;
static Glyph cache[Nglyphs];
static u32int blendtab[256];

static u32int
blend(u32int bg, u32int fg, int a)
{
	int br, bg_, bb, fr, fg_, fb, r, g, b, inv;

	inv = 255 - a;
	br = (bg >> 16) & 0xff;
	bg_ = (bg >> 8) & 0xff;
	bb = bg & 0xff;
	fr = (fg >> 16) & 0xff;
	fg_ = (fg >> 8) & 0xff;
	fb = fg & 0xff;
	r = (br * inv + fr * a) / 255;
	g = (bg_ * inv + fg_ * a) / 255;
	b = (bb * inv + fb * a) / 255;
	return (r << 16) | (g << 8) | b;
}

static void
loadfont(char *path)
{
	int fd;
	long sz, n;

	if(nfonts >= Maxfonts)
		die("too many fonts");
	fd = open(path, OREAD);
	if(fd < 0)
		die("can't open font: %s", path);
	sz = seek(fd, 0, 2);
	seek(fd, 0, 0);
	fontdata[nfonts] = emalloc(sz);
	n = readn(fd, fontdata[nfonts], sz);
	close(fd);
	if(n != sz)
		die("can't read font: %s", path);
	if(!stbtt_InitFont(&fonts[nfonts], fontdata[nfonts], stbtt_GetFontOffsetForIndex(fontdata[nfonts], 0)))
		die("can't init font: %s", path);
	scale[nfonts] = stbtt_ScaleForPixelHeight(&fonts[nfonts], Fontsz);
	nfonts++;
}

void
fontinit(char *dir)
{
	int fd, n, i, a;
	Dir *d;
	char path[256], *p;

	fd = open(dir, OREAD);
	if(fd < 0)
		die("can't open font dir: %s", dir);
	n = dirreadall(fd, &d);
	close(fd);
	if(n < 0)
		die("can't read font dir: %s", dir);
	for(i = 0; i < n; i++){
		p = strrchr(d[i].name, '.');
		if(p != nil && (strcmp(p, ".ttf") == 0 || strcmp(p, ".otf") == 0)){
			snprint(path, sizeof path, "%s/%s", dir, d[i].name);
			loadfont(path);
		}
	}
	free(d);
	if(nfonts == 0)
		die("no fonts in %s", dir);
	for(a = 0; a < 256; a++)
		blendtab[a] = blend(Colbg, Colfg, a);
}

static Glyph *
loadglyph(Rune r)
{
	Glyph *g;
	int f, gi, aw, lsb;

	if(r >= Nglyphs)
		return nil;
	g = &cache[r];
	if(g->adv != 0)
		return g;
	for(f = 0; f < nfonts; f++){
		gi = stbtt_FindGlyphIndex(&fonts[f], r);
		if(gi == 0)
			continue;
		stbtt_GetGlyphHMetrics(&fonts[f], gi, &aw, &lsb);
		g->bmp = stbtt_GetCodepointBitmap(&fonts[f], scale[f], scale[f], r, &g->w, &g->h, &g->ox, &g->oy);
		g->adv = (int)(aw * scale[f] + 0.5);
		if(g->adv < 1)
			g->adv = 1;
		return g;
	}
	g->adv = Fontsz / 2;
	return g;
}

int
fontadvance(Rune r)
{
	Glyph *g;

	g = loadglyph(r);
	return g != nil ? g->adv : Fontsz / 2;
}

void
putfont(u32int *buf, int w, int h, int px, int py, Rune r)
{
	Glyph *g;
	int i, j, x, y, a;

	g = loadglyph(r);
	if(g == nil || g->bmp == nil)
		return;
	for(j = 0; j < g->h; j++){
		y = py + j + g->oy + Fontsz - Fontbase;
		if(y < 0 || y >= h)
			continue;
		for(i = 0; i < g->w; i++){
			x = px + i + g->ox;
			if(x < 0 || x >= w)
				continue;
			a = g->bmp[j * g->w + i];
			if(a > 0)
				buf[y * w + x] = blendtab[a];
		}
	}
}
