124 float u0, v0, u1, v1;
132 float x0, y0, x1, y1;
133 float u0, v0, u1, v1;
165 int width,
int height,
void* user);
207 const unsigned char* ttf_data,
274 float* out_width,
float* out_height);
302#ifdef PICO_FONT_IMPLEMENTATION
305#ifndef PICO_FONT_GLYPH_PADDING
306#define PICO_FONT_GLYPH_PADDING 1
310#ifndef PICO_FONT_CACHE_INIT_SIZE
311#define PICO_FONT_CACHE_INIT_SIZE 256
315#ifndef PICO_FONT_INIT_PAGE_HEIGHT
316#define PICO_FONT_INIT_PAGE_HEIGHT 64
320 #define PICO_FONT_ASSERT(expr) ((void)0)
322 #ifndef PICO_FONT_ASSERT
324 #define PICO_FONT_ASSERT(expr) (assert(expr))
328#if !defined(PICO_FONT_CALLOC) || \
329 !defined(PICO_FONT_REALLOC) || \
330 !defined(PICO_FONT_FREE)
332 #define PICO_FONT_CALLOC(num, size) (calloc(num, size))
333 #define PICO_FONT_REALLOC(ptr, size) (realloc(ptr, size))
334 #define PICO_FONT_FREE(ptr) (free(ptr))
337#ifndef PICO_FONT_MEMSET
339 #define PICO_FONT_MEMSET memset
343#define PICO_FONT_ERROR ((size_t)-1)
345#include "stb_truetype.h"
367 unsigned char* pixels;
377 pf_atlas_page_t* pages;
379 size_t page_capacity;
386 size_t glyph_capacity;
389 pf_cache_entry_t* cache;
415static uint32_t pf_hash_key(uint32_t cp,
float size);
418static size_t pf_cache_lookup(
const pf_atlas_t* atlas, uint32_t key);
421static void pf_cache_insert_raw(pf_cache_entry_t* cache,
size_t cache_size,
422 uint32_t key,
size_t glyph_index);
425static int pf_cache_insert(
pf_atlas_t* atlas, uint32_t key,
429static size_t pf_atlas_add_page(
pf_atlas_t* atlas);
432static int pf_page_alloc(pf_atlas_page_t* page,
int w,
int h,
433 int* out_x,
int* out_y);
436static int pf_page_grow(pf_atlas_page_t* page,
int needed_height,
440static void pf_page_recompute_uvs(
pf_atlas_t* atlas,
size_t page_index);
443static int pf_atlas_alloc(
pf_atlas_t* atlas,
int w,
int h,
444 int* out_x,
int* out_y,
size_t* out_page);
450static uint32_t pf_utf8_decode(
const char** str);
453static void pf_walk_text(
pf_face_t* face,
const char* text,
458static bool pf_measure_cb(
const pf_quad_t* quad,
void* user);
464 PICO_FONT_ASSERT(page_width > 0);
465 PICO_FONT_ASSERT(max_page_height > 0);
472 atlas->page_width = page_width;
473 atlas->max_page_height = max_page_height;
475 atlas->cache_size = PICO_FONT_CACHE_INIT_SIZE;
476 atlas->cache = (pf_cache_entry_t*)PICO_FONT_CALLOC(atlas->cache_size,
477 sizeof(pf_cache_entry_t));
481 PICO_FONT_FREE(atlas);
486 if (pf_atlas_add_page(atlas) == PICO_FONT_ERROR)
488 PICO_FONT_FREE(atlas->cache);
489 PICO_FONT_FREE(atlas);
501 for (
size_t i = 0; i < atlas->page_count; i++)
503 PICO_FONT_FREE(atlas->pages[i].pixels);
506 PICO_FONT_FREE(atlas->pages);
507 PICO_FONT_FREE(atlas->glyphs);
508 PICO_FONT_FREE(atlas->cache);
509 PICO_FONT_FREE(atlas);
513 const unsigned char* ttf_data,
516 PICO_FONT_ASSERT(atlas != NULL);
517 PICO_FONT_ASSERT(ttf_data != NULL);
518 PICO_FONT_ASSERT(pixel_height > 0.0f);
526 face->size = pixel_height;
528 int offset = stbtt_GetFontOffsetForIndex(ttf_data, 0);
531 PICO_FONT_FREE(face);
535 if (!stbtt_InitFont(&face->info, ttf_data, offset))
537 PICO_FONT_FREE(face);
541 face->scale = stbtt_ScaleForPixelHeight(&face->info, pixel_height);
543 int ascent, descent, gap;
544 stbtt_GetFontVMetrics(&face->info, &ascent, &descent, &gap);
545 face->ascent = (int)(ascent * face->scale + 0.5f);
546 face->descent = (int)(descent * face->scale - 0.5f);
547 face->line_gap = (int)(gap * face->scale + 0.5f);
556 PICO_FONT_FREE(face);
561 PICO_FONT_ASSERT(face != NULL);
564 uint32_t key = pf_hash_key(codepoint, face->size);
567 size_t cached = pf_cache_lookup(atlas, key);
568 if (cached != PICO_FONT_ERROR)
573 if (glyph->
codepoint == codepoint && glyph->
size == face->size)
586 int glyph_index = stbtt_FindGlyphIndex(&face->info, (
int)codepoint);
588 int advance_raw, lsb;
589 stbtt_GetGlyphHMetrics(&face->info, glyph_index, &advance_raw, &lsb);
593 glyph.
size = face->size;
595 glyph.
advance_x = advance_raw * face->scale;
598 if (stbtt_IsGlyphEmpty(&face->info, glyph_index))
603 size_t index = pf_glyph_push(atlas, &glyph);
604 if (index == PICO_FONT_ERROR)
607 pf_cache_insert(atlas, key, index);
608 return &atlas->glyphs[index];
612 stbtt_GetGlyphBitmapBox(&face->info, glyph_index,
613 face->scale, face->scale,
618 if (bw <= 0 || bh <= 0)
620 size_t index = pf_glyph_push(atlas, &glyph);
622 if (index == PICO_FONT_ERROR)
625 pf_cache_insert(atlas, key, index);
626 return &atlas->glyphs[index];
632 if (pf_atlas_alloc(atlas, bw, bh, &ax, &ay, &ap) != 0)
638 pf_atlas_page_t* page = &atlas->pages[ap];
639 stbtt_MakeGlyphBitmap(&face->info,
640 page->pixels + ay * page->width + ax,
642 face->scale, face->scale,
654 float inv_w = 1.0f / (float)page->width;
655 float inv_h = 1.0f / (float)page->height;
657 glyph.
u0 = (float)ax * inv_w;
658 glyph.
v0 = (float)ay * inv_h;
659 glyph.
u1 = (float)(ax + bw) * inv_w;
660 glyph.
v1 = (float)(ay + bh) * inv_h;
662 size_t index = pf_glyph_push(atlas, &glyph);
664 if (index == PICO_FONT_ERROR)
667 pf_cache_insert(atlas, key, index);
668 return &atlas->glyphs[index];
675 PICO_FONT_ASSERT(face != NULL);
676 PICO_FONT_ASSERT(x != NULL);
677 PICO_FONT_ASSERT(y != NULL);
682 pf_walk_text(face, text, x, y, cb, user);
690 for (
size_t i = 0; i < atlas->page_count; i++)
692 pf_atlas_page_t* page = &atlas->pages[i];
697 if (!cb(i, page->pixels, page->width, page->height, user))
707 float* out_width,
float* out_height)
709 PICO_FONT_ASSERT(face != NULL);
723 pf_measure_state_t state = { 0, 0 };
724 pf_walk_text(face, text, &x, &y, pf_measure_cb, &state);
730 float line_height = (float)(face->ascent - face->descent + face->line_gap);
733 *out_width = state.max_x;
736 *out_height = (state.max_x > 0) ? line_height : 0;
741 PICO_FONT_ASSERT(face != NULL);
742 PICO_FONT_ASSERT(metrics != NULL);
744 metrics->
ascent = (float)face->ascent;
745 metrics->descent = (float)face->descent;
746 metrics->line_gap = (float)face->line_gap;
747 metrics->line_height = (float)(face->ascent - face->descent + face->line_gap);
752 PICO_FONT_ASSERT(face != NULL);
754 int g1 = stbtt_FindGlyphIndex(&face->info, (
int)cp1);
755 int g2 = stbtt_FindGlyphIndex(&face->info, (
int)cp2);
757 return stbtt_GetGlyphKernAdvance(&face->info, g1, g2) * face->scale;
762static uint32_t pf_hash_key(uint32_t cp,
float size)
764 uint32_t x = cp ^ (uint32_t)(size * 100.f);
765 x = ((x >> 16) ^ x) * 0x45d9f3b;
766 x = ((x >> 16) ^ x) * 0x45d9f3b;
771static size_t pf_cache_lookup(
const pf_atlas_t* atlas, uint32_t key)
773 size_t mask = atlas->cache_size - 1;
774 size_t index = (size_t)(key) & mask;
776 for (
size_t i = 0; i < atlas->cache_size; i++)
778 size_t slot = (index + i) & mask;
780 if (atlas->cache[slot].key == key)
781 return atlas->cache[slot].glyph_index;
783 if (atlas->cache[slot].key == 0)
784 return PICO_FONT_ERROR;
787 return PICO_FONT_ERROR;
790static void pf_cache_insert_raw(pf_cache_entry_t* cache,
size_t cache_size,
791 uint32_t key,
size_t glyph_index)
793 PICO_FONT_ASSERT(key != 0);
795 size_t mask = cache_size - 1;
796 size_t index = (size_t)(key) & mask;
798 for (
size_t i = 0; i < cache_size; i++)
800 size_t slot = (index + i) & mask;
802 if (cache[slot].key == 0)
804 cache[slot].key = key;
805 cache[slot].glyph_index = glyph_index;
810 PICO_FONT_ASSERT(
false);
813static int pf_cache_insert(
pf_atlas_t* atlas, uint32_t key,
size_t glyph_index)
816 size_t used = atlas->glyph_count;
818 if (used * 10 > atlas->cache_size * 7)
820 size_t new_size = atlas->cache_size * 2;
822 pf_cache_entry_t* new_cache = (pf_cache_entry_t*)PICO_FONT_CALLOC(new_size,
823 sizeof(pf_cache_entry_t));
829 for (
size_t i = 0; i < atlas->cache_size; i++)
831 if (atlas->cache[i].key != 0)
833 pf_cache_insert_raw(new_cache, new_size,
835 atlas->cache[i].glyph_index);
839 PICO_FONT_FREE(atlas->cache);
841 atlas->cache = new_cache;
842 atlas->cache_size = new_size;
845 pf_cache_insert_raw(atlas->cache, atlas->cache_size, key, glyph_index);
851static size_t pf_atlas_add_page(
pf_atlas_t* atlas)
853 if (atlas->page_count >= atlas->page_capacity)
855 size_t new_capacity = atlas->page_capacity ? atlas->page_capacity * 2 : 4;
857 pf_atlas_page_t* new_array = (pf_atlas_page_t*)PICO_FONT_REALLOC(atlas->pages,
858 new_capacity *
sizeof(pf_atlas_page_t));
861 return PICO_FONT_ERROR;
863 atlas->pages = new_array;
864 atlas->page_capacity = new_capacity;
867 size_t index = atlas->page_count;
869 pf_atlas_page_t* page = &atlas->pages[index];
870 PICO_FONT_MEMSET(page, 0,
sizeof(*page));
871 page->width = atlas->page_width;
874 if (pf_page_grow(page, PICO_FONT_INIT_PAGE_HEIGHT,
875 atlas->max_page_height) != 0)
877 return PICO_FONT_ERROR;
886static int pf_page_alloc(pf_atlas_page_t* page,
int w,
int h,
887 int* out_x,
int* out_y)
889 int pad = PICO_FONT_GLYPH_PADDING;
894 if (page->shelf.cursor_x + pw <= page->width &&
895 page->shelf.cursor_y + ph <= page->height)
897 if (ph > page->shelf.shelf_height)
898 page->shelf.shelf_height = ph;
900 *out_x = page->shelf.cursor_x;
901 *out_y = page->shelf.cursor_y;
902 page->shelf.cursor_x += pw;
908 page->shelf.cursor_x = 0;
909 page->shelf.cursor_y += page->shelf.shelf_height;
910 page->shelf.shelf_height = 0;
912 if (page->shelf.cursor_x + pw <= page->width &&
913 page->shelf.cursor_y + ph <= page->height)
915 page->shelf.shelf_height = ph;
917 *out_x = page->shelf.cursor_x;
918 *out_y = page->shelf.cursor_y;
919 page->shelf.cursor_x += pw;
932static int pf_page_grow(pf_atlas_page_t* page,
int needed_height,
int max_height)
934 PICO_FONT_ASSERT(page != NULL);
935 PICO_FONT_ASSERT(max_height > 0);
937 if (needed_height <= page->height)
940 if (needed_height > max_height)
943 int new_height = page->height > 0 ? page->height : 1;
944 while (new_height < needed_height)
949 if (new_height > max_height)
950 new_height = max_height;
952 unsigned char* new_pixels = (
unsigned char*)PICO_FONT_REALLOC(page->pixels,
953 (
size_t)page->width * (size_t)new_height);
959 PICO_FONT_MEMSET(new_pixels + (
size_t)page->width * (
size_t)page->height, 0,
960 (
size_t)page->width *
961 (
size_t)(new_height - page->height));
963 page->pixels = new_pixels;
964 page->height = new_height;
971static void pf_page_recompute_uvs(
pf_atlas_t* atlas,
size_t page_index)
973 PICO_FONT_ASSERT(page_index < atlas->page_count);
974 PICO_FONT_ASSERT(atlas->pages[page_index].height > 0);
976 float inv_h = 1.0f / (float)atlas->pages[page_index].height;
978 for (
size_t i = 0; i < atlas->glyph_count; i++)
982 if (g->
page != page_index)
995static int pf_atlas_alloc(
pf_atlas_t* atlas,
int w,
int h,
996 int* out_x,
int* out_y,
size_t* out_page)
998 int pad = PICO_FONT_GLYPH_PADDING;
1002 if (atlas->page_count > 0)
1004 size_t page_index = atlas->page_count - 1;
1005 pf_atlas_page_t* page = &atlas->pages[page_index];
1007 if (pf_page_alloc(page, w, h, out_x, out_y) == 0)
1009 *out_page = page_index;
1014 int needed = page->shelf.cursor_y + page->shelf.shelf_height + ph;
1016 if (pf_page_grow(page, needed, atlas->max_page_height) == 0)
1018 pf_page_recompute_uvs(atlas, page_index);
1020 if (pf_page_alloc(page, w, h, out_x, out_y) == 0)
1022 *out_page = page_index;
1029 size_t page_index = pf_atlas_add_page(atlas);
1031 if (page_index == PICO_FONT_ERROR)
1035 pf_atlas_page_t* page = &atlas->pages[page_index];
1036 if (pf_page_grow(page, ph, atlas->max_page_height) != 0)
1041 if (pf_page_alloc(page, w, h, out_x, out_y) == 0)
1043 *out_page = page_index;
1053 if (atlas->glyph_count >= atlas->glyph_capacity)
1055 size_t new_capacity = atlas->glyph_capacity ? atlas->glyph_capacity * 2 : 64;
1061 return PICO_FONT_ERROR;
1063 atlas->glyphs = new_array;
1064 atlas->glyph_capacity = new_capacity;
1067 size_t index = atlas->glyph_count++;
1068 atlas->glyphs[index] = *glyph;
1074static uint32_t pf_utf8_decode(
const char** str)
1076 const unsigned char* s = (
const unsigned char*)*str;
1080 if (s[0] < 0x80) { cp = s[0]; n = 1; }
1081 else if (s[0] < 0xC0) { cp = 0xFFFD; n = 1; }
1082 else if (s[0] < 0xE0) { cp = s[0] & 0x1F; n = 2; }
1083 else if (s[0] < 0xF0) { cp = s[0] & 0x0F; n = 3; }
1084 else if (s[0] < 0xF8) { cp = s[0] & 0x07; n = 4; }
1085 else { cp = 0xFFFD; n = 1; }
1087 for (
int i = 1; i < n; i++)
1089 if ((s[i] & 0xC0) != 0x80)
1091 *str = (
const char*)(s + i);
1094 cp = (cp << 6) | (s[i] & 0x3F);
1098 if ((n == 2 && cp < 0x80) ||
1099 (n == 3 && cp < 0x800) ||
1100 (n == 4 && cp < 0x10000) ||
1101 (cp >= 0xD800 && cp <= 0xDFFF) ||
1107 *str = (
const char*)(s + n);
1113static void pf_walk_text(
pf_face_t* face,
const char* text,
1117 const char* s = text;
1118 uint32_t prev_cp = 0;
1122 uint32_t cp = pf_utf8_decode(&s);
1143 q.y0 = *y + (float)g->
offset_y + (
float)face->ascent;
1144 q.x1 = q.x0 + (float)g->
page_w;
1145 q.y1 = q.y0 + (float)g->
page_h;
1161static bool pf_measure_cb(
const pf_quad_t* quad,
void* user)
1163 pf_measure_state_t* st = (pf_measure_state_t*)user;
1165 if (quad->
x1 > st->max_x)
1166 st->max_x = quad->
x1;
1168 if (quad->
y1 > st->max_y)
1169 st->max_y = quad->
y1;
void pf_upload_atlas(pf_atlas_t *atlas, pf_upload_callback_fn cb, void *user)
Iterate over dirty pages and invoke the callback for each one.
struct pf_atlas_t pf_atlas_t
Definition pico_font.h:98
bool(* pf_upload_callback_fn)(size_t page, const unsigned char *pixels, int width, int height, void *user)
Callback invoked for each dirty atlas page during pf_upload_atlas.
Definition pico_font.h:164
struct pf_face_t pf_face_t
Definition pico_font.h:99
float pf_get_kerning(const pf_face_t *face, uint32_t cp1, uint32_t cp2)
Get the horizontal kerning adjustment between two codepoints.
void pf_destroy_face(pf_face_t *face)
Destroys a font face.
void pf_destroy_atlas(pf_atlas_t *atlas)
Destroys a font atlas and frees all associated pages and glyphs.
void pf_get_metrics(const pf_face_t *face, pf_metrics_t *metrics)
Retrieve vertical font metrics for a face.
bool(* pf_draw_callback_fn)(const pf_quad_t *quad, void *user)
Callback invoked for each glyph quad during text drawing.
Definition pico_font.h:153
void pf_draw_text(pf_face_t *face, const char *text, float *x, float *y, pf_draw_callback_fn cb, void *user)
Lay out and emit quads for a UTF-8 string.
const pf_glyph_t * pf_get_glyph(pf_face_t *face, uint32_t codepoint)
Get (or rasterize) a single glyph.
pf_atlas_t * pf_create_atlas(int page_width, int max_page_height)
Allocates and initializes a font atlas.
pf_face_t * pf_create_face(pf_atlas_t *atlas, const unsigned char *ttf_data, float pixel_height)
Create a font face at a given pixel height.
void pf_measure_text(pf_face_t *face, const char *text, float *out_width, float *out_height)
Measure a UTF-8 string without drawing.
UV coordinates and metrics for a cached glyph.
Definition pico_font.h:105
float advance_x
Definition pico_font.h:121
int offset_x
Definition pico_font.h:118
int glyph_index
Definition pico_font.h:108
uint32_t codepoint
Definition pico_font.h:106
float v1
Definition pico_font.h:124
int page_h
Definition pico_font.h:112
int page_x
Definition pico_font.h:111
size_t page
Definition pico_font.h:115
float size
Definition pico_font.h:107
int page_w
Definition pico_font.h:112
int offset_y
Definition pico_font.h:118
float v0
Definition pico_font.h:124
float u1
Definition pico_font.h:124
float u0
Definition pico_font.h:124
int page_y
Definition pico_font.h:111
Vertical font metrics for a face.
Definition pico_font.h:141
float ascent
Distance from baseline to top of tallest glyph.
Definition pico_font.h:142
float line_gap
Extra spacing between lines.
Definition pico_font.h:144
float descent
Distance from baseline to bottom (typically negative).
Definition pico_font.h:143
float line_height
Recommended line advance (ascent - descent + line_gap).
Definition pico_font.h:145
Quad emitted by pf_draw_text.
Definition pico_font.h:131
float u0
Definition pico_font.h:133
size_t page
Definition pico_font.h:134
float x1
Definition pico_font.h:132
float y1
Definition pico_font.h:132
float x0
Definition pico_font.h:132