#include"k3font.h" #include"k3batch.h" #include #include"gl.h" struct k3Font *k3FontCreate() { struct k3Font *ret = calloc(sizeof(*ret), 1); return ret; } static int cmpglyph(const void *a, const void *b) { return *(const uint32_t*) a - *(const uint32_t*) b; } int k3FontLoad(struct k3Font *this, const uint8_t *buf, size_t len, k3FontTexLoader texldr) { if(*(uint32_t*) buf != 0x03464D42) { return 0; } const uint8_t *end = buf + len; buf += 4; uint16_t pages = 0; while(buf + 5 < end) { uint8_t blockType = *buf; uint32_t blockSize = *(uint32_t*) (buf + 1); buf += 5; if(blockType == 1) { //Info block buf += 14; while(*buf) buf++; buf++; } else if(blockType == 2) { //Common block this->lineScale = 1.f / *(uint16_t*) buf; buf += 2; this->baseline = *(uint16_t*) buf; buf += 2; this->texW = *(uint16_t*) buf; buf += 2; this->texH = *(uint16_t*) buf; buf += 2; pages = *(uint16_t*) buf; buf += 7; } else if(blockType == 3) { //Pages block if(pages == 0) return 0; this->pageCount = pages; this->pages = malloc(sizeof(*this->pages) * this->pageCount); for(size_t i = 0; i < this->pageCount; i++) { this->pages[i] = texldr(this, buf); buf += strlen(buf) + 1; } } else if(blockType == 4) { //Chars block size_t num = blockSize / 20; this->glyphs = calloc(sizeof(*this->glyphs), this->glyphCount = num); memcpy(this->glyphs, buf, num * 20); qsort(this->glyphs, num, sizeof(*this->glyphs), cmpglyph); buf += blockSize; } else if(blockType == 5) { //Kerning block // Ignore kerning for now buf += blockSize; } } return 1; } static uint32_t read_utf8(const char **txt_) { const uint8_t **txt = (void*) txt_; if(**txt == 0) { return 0; } else if(**txt < 0x80) { return *(*txt)++; } else if(**txt < 0xE0) { uint32_t ret = ((*(*txt)++) & 0x1F) << 6; ret |= (*(*txt)++) & 0x3F; return ret; } else if(**txt < 0xF0) { uint32_t ret = ((*(*txt)++) & 0x0F) << 12; ret |= ((*(*txt)++) & 0x3F) << 6; ret |= (*(*txt)++) & 0x3F; return ret; } else { uint32_t ret = ((*(*txt)++) & 0x07) << 18; ret |= ((*(*txt)++) & 0x3F) << 12; ret |= ((*(*txt)++) & 0x3F) << 6; ret |= (*(*txt)++) & 0x3F; return ret; } } void k3FontSz(struct k3Font *this, float sz, const char *txt, float wall, struct k3RectF *ret) { if(wall < 0) { wall = HUGE_VALF; } float maxX = 0; float x = 0, y = sz; while(1) { uint32_t cp = read_utf8(&txt); if(!cp) break; if(cp == 10) { x = 0; y += sz; } struct k3FontGlyph *g = k3FontGetGlyph(this, cp); if(!g) continue; if(x + g->width > wall) { x = 0; y += sz; } x += g->xadvance * this->lineScale * sz; maxX = fmaxf(maxX, x); } ret->w = maxX; ret->h = y; } void k3FontDraw(struct k3Font *this, float xStart, float yStart, float sz, const char *txt, float wall, vec4 color) { if(wall < 0) { wall = HUGE_VALF; } float x = xStart, y = yStart; while(1) { uint32_t cp = read_utf8(&txt); if(!cp) break; if(cp == 10) { x = xStart; y -= sz; } struct k3FontGlyph *g = k3FontGetGlyph(this, cp); if(!g) continue; if(x + g->width - xStart > wall) { x = xStart; y -= sz; } struct k3Tex *tex = this->pages[g->page]; size_t texW = this->texW; size_t texH = this->texH; k3BatchAdd(tex, (struct k3RectF) {(float) g->x / texW, (float) g->y / texH, (float) g->width / texW, (float) g->height / texH}, (struct k3RectF) { x + g->xoffset * this->lineScale * sz, y + ((-g->height - g->yoffset) * this->lineScale + 1) * sz, g->width * this->lineScale * sz, g->height * this->lineScale * sz }, 0, color, 0); x += g->xadvance * this->lineScale * sz; } k3BatchFlush(); } struct k3FontGlyph *k3FontGetGlyph(struct k3Font *this, uint32_t cp) { return bsearch(&cp, this->glyphs, this->glyphCount, sizeof(*this->glyphs), cmpglyph); }