diff --git a/test/test_bittype.c3 b/test/test_bittype.c3 new file mode 100644 index 0000000..e9802c9 --- /dev/null +++ b/test/test_bittype.c3 @@ -0,0 +1,10 @@ +import std::io; +import std::collections::bitset; + +def Bits = bitset::BitSet(<128>); + +fn void main() +{ + Bits b; + io::printn($typeof(b.data[0]).sizeof); +} diff --git a/test/test_custom_hash.c3 b/test/test_custom_hash.c3 new file mode 100644 index 0000000..fc90f11 --- /dev/null +++ b/test/test_custom_hash.c3 @@ -0,0 +1,14 @@ +import std::collections::map; + +def Codepoint = uint; +fn uint Codepoint.hash(Codepoint code) => code < 128 ? code : ((uint)code).hash(); +def CodeMap = map::HashMap(); + + +fn int main() +{ + CodeMap m; + m.new_init(); + m.free(); + return 0; +} diff --git a/test/ugui_font.c3 b/test/ugui_font.c3 new file mode 100644 index 0000000..ec1fc03 --- /dev/null +++ b/test/ugui_font.c3 @@ -0,0 +1,226 @@ +module ugui; + +import cache; +//#include +//#include + +//#include "stb_truetype.h" +//#include "stbimage_write.h" + +// unicode code point, different type for a different hash +def Codepoint = uint; + +/* width and height of a glyph contain the kering advance + * (u,v) + * +-------------*---+ - + * | ^ | | ^ + * | |oy | | | + * | v | | | + * | .ii. | | | + * | @@@@@@. |<->| | + * | V@Mio@@o |adv| |h + * | :i. V@V | | | + * | :oM@@M | | | + * | :@@@MM@M | | | + * | @@o o@M | | | + * |<->:@@. M@M | | | + * |ox @@@o@@@@ | | | + * | :M@@V:@@.| | v + * +-------------*---+ - + * |<------------->| + * w + */ +struct Glyph { + Codepoint code; + uint u, v; + ushort w, h, a, x, y; +} + +def GlyphCache = cache::Cache(); + +// identity map the ASCII range +fn uint Codepoint.hash(Codepoint code) => code < 128 ? code : ((uint)code).hash(); + +struct FontAtlas { + uint width, height; + char* atlas; + uint glyph_max_w, glyph_max_h; + int size; + int file_size; + char *file; + void *priv; +} + + +macro is_utf8(char c) => c & 0x80; +const uint BDEPTH = 1; +const uint BORDER = 4; + +// FIXME: as of now only monospaced fonts look decent since no +// kerning information is stored + +struct Priv @private { + stbtt_fontinfo stb; + float scale; + int baseline; + unsigned char *bitmap; + struct cache c; +} +//#define PRIV(x) ((struct priv *)x->priv) + + +struct font_atlas * font_init(void) +{ + struct font_atlas *p = emalloc(sizeof(struct font_atlas)); + memset(p, 0, sizeof(struct font_atlas)); + p->priv = emalloc(sizeof(struct priv)); + memset(p->priv, 0, sizeof(struct priv)); + PRIV(p)->c = cache_init(); + return p; +} + + +// loads a font into memory, storing all the ASCII characters in the atlas, each font +// atlas structure holds glyphs of a specific size in pixels +// NOTE: size includes ascend and descend (so 12 does not mean that 'A' is 12px tall) +int font_load(struct font_atlas *atlas, const char *path, int size) +{ + if (!atlas || !path) + return -1; + + int err; + + dump_file(path, &(atlas->file), &(atlas->file_size)); + + err = stbtt_InitFont(&(PRIV(atlas)->stb), (unsigned char *)atlas->file, 0); + if (err == 0) return -1; + + int ascent, descent, linegap, baseline; + int x0,y0,x1,y1; + float scale; + stbtt_GetFontVMetrics(&(PRIV(atlas)->stb), &ascent, &descent, &linegap); + stbtt_GetFontBoundingBox(&(PRIV(atlas)->stb), &x0, &y0, &x1, &y1); + scale = stbtt_ScaleForPixelHeight(&(PRIV(atlas)->stb), size); + baseline = scale * -y0; + atlas->glyph_max_w = (scale*x1) - (scale*x0); + atlas->glyph_max_h = (baseline+scale*y1) - (baseline+scale*y0); + atlas->atlas = emalloc(CACHE_SIZE*BDEPTH*atlas->glyph_max_w*atlas->glyph_max_h); + memset(atlas->atlas, 0, CACHE_SIZE*BDEPTH*atlas->glyph_max_w*atlas->glyph_max_h); + PRIV(atlas)->baseline = atlas->glyph_max_h - baseline; + PRIV(atlas)->scale = scale; + PRIV(atlas)->bitmap = emalloc(BDEPTH*atlas->glyph_max_w*atlas->glyph_max_h); + // FIXME: make this a square atlas + atlas->width = atlas->glyph_max_w*CACHE_SIZE/4; + atlas->height = atlas->glyph_max_h*4; + atlas->size = size; + + // preallocate all ascii characters + for (char c = ' '; c <= '~'; c++) { + if (!font_get_glyph_texture(atlas, c, NULL)) + return -1; + } + + return 0; +} + + +int font_free(struct font_atlas *atlas) +{ + efree(atlas->atlas); + efree(atlas->file); + efree(PRIV(atlas)->bitmap); + cache_free(&PRIV(atlas)->c); + efree(atlas->priv); + efree(atlas); + return 0; +} + + +// TODO: time and take the median of the time it takes to generate the cache and +// the time it takes to draw the glyph +const struct font_glyph * font_get_glyph_texture(struct font_atlas *atlas, unsigned int code, int *updated) +{ + int _u = 0; + if (!updated) updated = &_u; + + const struct font_glyph *r; + if ((r = cache_search(&PRIV(atlas)->c, code)) != NULL) { + *updated = 0; + return r; + } + + *updated = 1; + // generate the sdf and put it into the cache + // TODO: generate the whole block at once + int idx = stbtt_FindGlyphIndex(&PRIV(atlas)->stb, code); + int x0,y0,x1,y1,gw,gh,l,off_x,off_y,adv,base; + base = atlas->glyph_max_h - PRIV(atlas)->baseline; + stbtt_GetGlyphBitmapBoxSubpixel( + &PRIV(atlas)->stb, + idx, + PRIV(atlas)->scale, + PRIV(atlas)->scale, + 0,0, + &x0,&y0, + &x1, &y1); + gw = x1 - x0; + gh = y1 - y0; + stbtt_GetGlyphHMetrics(&PRIV(atlas)->stb, idx, &adv, &l); + adv *= PRIV(atlas)->scale; + off_x = PRIV(atlas)->scale*l; + off_y = atlas->glyph_max_h+y0; + stbtt_MakeGlyphBitmapSubpixel( + &PRIV(atlas)->stb, + PRIV(atlas)->bitmap, + atlas->glyph_max_w, + atlas->glyph_max_h, + atlas->glyph_max_w, + PRIV(atlas)->scale, + PRIV(atlas)->scale, + 0, 0, + idx); + + // TODO: bounds check usign atlas height + // TODO: clear spot area in the atlas before writing on it + unsigned int spot = cache_get_free_spot(&PRIV(atlas)->c); + unsigned int ty = ((atlas->glyph_max_w * spot) / atlas->width) * atlas->glyph_max_h; + unsigned int tx = (atlas->glyph_max_w * spot) % atlas->width; + unsigned int w = atlas->width; + + unsigned char *a = (void *)atlas->atlas; + + //printf("max:%d %d spot:%d : %d %d %d %d\n", atlas->glyph_max_w, atlas->glyph_max_h, spot, tx, ty, off_x, off_y); + + for (int y = 0; y < gh; y++) { + for (int x = 0; x < gw; x++) { + int c, r; + r = (ty+y)*w; + c = tx+x; + a[r+c] = PRIV(atlas)->bitmap[y*atlas->glyph_max_w+x]; + } + } + + struct font_glyph g = { + .codepoint = code, + .u = tx, + .v = ty, + .w = gw, + .h = gh, + .x = off_x, + .y = off_y-base, + .a = adv, + }; + return cache_insert_at(&PRIV(atlas)->c, &g, g.codepoint, spot); +} + + +void font_dump(const struct font_atlas *atlas, const char *path) +{ + stbi_write_png( + path, + atlas->width, + atlas->height, + BDEPTH, + atlas->atlas, + BDEPTH*atlas->width); +}