#include "memory.h" #include "plat.h" #include "render.h" #include "stb_rect_pack.h" #include "stb_truetype.h" #include typedef struct { Bitmap bmp; stbtt_bakedchar glyphs[max_glyphset]; } Glyph_Set; struct Font { const void* data; Heap* heap; stbtt_fontinfo info; Glyph_Set* sets[max_glyphset]; int size, height; }; int font_height(Font* f) { return f->height; } static const char* utf8_to_codepoint( const char* p, unsigned* dst ) { unsigned res, n; switch (*p & 0xf0) { case 0xf0 : res = *p & 0x07; n = 3; break; case 0xe0 : res = *p & 0x0f; n = 2; break; case 0xd0 : case 0xc0 : res = *p & 0x1f; n = 1; break; default : res = *p; n = 0; break; } while (n--) { res = (res << 6) | (*(++p) & 0x3f); } *dst = res; return p + 1; } static Glyph_Set* load_glyph_set( Font* font, int idx ) { Glyph_Set* gs; Bitmap* bmp; int r, i; int ascent, descent, linegap, scaled_ascent; float s; gs = heap_alloc(font->heap, sizeof *gs); bmp = &gs->bmp; bmp->w = 512; bmp->h = 512; retry: bmp->pixels = heap_alloc( font->heap, bmp->w * bmp->h * 4 ); s = stbtt_ScaleForMappingEmToPixels(&font->info, 1) / stbtt_ScaleForPixelHeight(&font->info, 1); r = stbtt_BakeFontBitmap( font->data, 0, font->size * s, (unsigned char*)bmp->pixels, bmp->w, bmp->h, idx * 256, 256, gs->glyphs ); if (r <= 0) { bmp->w *= 2; bmp->h *= 2; heap_free(font->heap, bmp->pixels); goto retry; } stbtt_GetFontVMetrics(&font->info, &ascent, &descent, &linegap); s = stbtt_ScaleForMappingEmToPixels(&font->info, font->size); scaled_ascent = (int)(ascent * s + 0.5f); for (i = 0; i < 256; i++) { gs->glyphs[i].yoff += scaled_ascent; gs->glyphs[i].xadvance = (float)floor(gs->glyphs[i].xadvance); } for (i = bmp->w * bmp->h - 1; i >= 0; i--) { unsigned char n = ((unsigned char*)bmp->pixels)[i]; bmp->pixels[i].r = 255; bmp->pixels[i].g = 255; bmp->pixels[i].b = 255; bmp->pixels[i].a = n; } return gs; } static Glyph_Set* get_glyph_set( Font* font, int codepoint ) { int idx = (codepoint >> 8) % max_glyphset; if (!font->sets[idx]) { font->sets[idx] = load_glyph_set(font, idx); } return font->sets[idx]; } void init_font( Font* font, Heap* heap, const unsigned char* raw, int size ) { int r, i; int ascent, descent, linegap; float scale; font->heap = heap; font->data = raw; font->size = size; stbtt_bakedchar* g; for (i = 0; i < max_glyphset; i++) font->sets[i] = 0; r = stbtt_InitFont(&font->info, font->data, 0); if (!r) { print("Invalid font.\n"); pbreak(error_font); } stbtt_GetFontVMetrics( &font->info, &ascent, &descent, &linegap ); scale = stbtt_ScaleForMappingEmToPixels( &font->info, size ); font->height = (int)( (ascent - descent + linegap) * scale + 0.5f ); g = get_glyph_set(font, '\n')->glyphs; g['\t'].x1 = g['\t'].x0; g['\n'].x1 = g['\n'].x0; } Font* new_font( Heap* h, const unsigned char* raw, int size ) { Font* f; f = heap_alloc(h, sizeof *f); init_font(f, h, raw, size); return f; } Rectangle text_rect( Font* font, const char* text ) { const char* p = text; unsigned codepoint; int x = 0; Glyph_Set* gs; stbtt_bakedchar* g; Rectangle re = { 0 }, r; while (*p) { p = utf8_to_codepoint(p, &codepoint); gs = get_glyph_set(font, codepoint); g = &gs->glyphs[codepoint & 0xff]; r.x = x + (int)g->xoff; r.y = (int)g->yoff; r.w = (int)g->x1 - g->x0; r.h = (int)g->y1 - g->y0; rect_merge(&re, &r); x += (int)g->xadvance; } return re; } #define rf(expr) \ const char* p = text; \ unsigned codepoint; \ Glyph_Set* gs; \ stbtt_bakedchar* g; \ Rectangle r; \ while (*p) { \ p = utf8_to_codepoint(p, &codepoint); \ gs = get_glyph_set(font, codepoint); \ g = &gs->glyphs[codepoint & 0xff]; \ r.x = (int)g->x0; \ r.y = (int)g->y0; \ r.w = (int)g->x1 - g->x0; \ r.h = (int)g->y1 - g->y0; \ expr; \ x += (int)g->xadvance; \ } void rfont_text( Font* font, int x, int y, const char* text ) { rf(render_bitmap( &gs->bmp, x + (int)g->xoff, y + (int)g->yoff, &r )); } void rfont_text_col( Font* font, int x, int y, const char* text, Colour colour ) { rf(render_bitmap_col( &gs->bmp, x + (int)g->xoff, y + (int)g->yoff, &r, colour )); } #undef rf #define STB_RECT_PACK_IMPLEMENTATION #define STB_TRUETYPE_IMPLEMENTATION #include "stb_rect_pack.h" #include "stb_truetype.h"