180 lines
3.9 KiB
C
180 lines
3.9 KiB
C
#include"k3font.h"
|
|
|
|
#include"k3batch.h"
|
|
#include<string.h>
|
|
#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);
|
|
}
|