131 float u0, v0, u1, v1;
139 float x0, y0, x1, y1;
140 float u0, v0, u1, v1;
176 int width,
int height,
void* user);
216 const unsigned char* ttf_data,
217 size_t ttf_data_size,
284 float* out_width,
float* out_height);
312#ifdef PICO_FONT_IMPLEMENTATION
315#ifndef PICO_FONT_GLYPH_PADDING
316#define PICO_FONT_GLYPH_PADDING 1
320#ifndef PICO_FONT_CACHE_INIT_SIZE
321#define PICO_FONT_CACHE_INIT_SIZE 256
325#ifndef PICO_FONT_INIT_PAGE_HEIGHT
326#define PICO_FONT_INIT_PAGE_HEIGHT 64
330 #define PICO_FONT_ASSERT(expr) ((void)0)
332 #ifndef PICO_FONT_ASSERT
334 #define PICO_FONT_ASSERT(expr) (assert(expr))
338#if !defined(PICO_FONT_MALLOC) || \
339 !defined(PICO_FONT_CALLOC) || \
340 !defined(PICO_FONT_REALLOC) || \
341 !defined(PICO_FONT_FREE)
343 #define PICO_FONT_MALLOC(size) (malloc(size))
344 #define PICO_FONT_CALLOC(num, size) (calloc(num, size))
345 #define PICO_FONT_REALLOC(ptr, size) (realloc(ptr, size))
346 #define PICO_FONT_FREE(ptr) (free(ptr))
349#ifndef PICO_FONT_MEMSET
351 #define PICO_FONT_MEMSET memset
354#ifndef PICO_FONT_MEMCPY
356 #define PICO_FONT_MEMCPY memcpy
360#define PICO_FONT_ERROR ((size_t)-1)
362#include "stb_truetype.h"
384 unsigned char* pixels;
394 pf_atlas_page_t* pages;
396 size_t page_capacity;
403 size_t glyph_capacity;
406 pf_cache_entry_t* cache;
414 unsigned char* ttf_data;
433static uint32_t pf_hash_key(uint32_t cp,
float size);
436static size_t pf_cache_lookup(
const pf_atlas_t* atlas, uint32_t key);
439static void pf_cache_insert_raw(pf_cache_entry_t* cache,
size_t cache_size,
440 uint32_t key,
size_t glyph_index);
443static int pf_cache_insert(
pf_atlas_t* atlas, uint32_t key,
447static size_t pf_atlas_add_page(
pf_atlas_t* atlas);
450static int pf_page_alloc(pf_atlas_page_t* page,
int w,
int h,
451 int* out_x,
int* out_y);
454static int pf_page_grow(pf_atlas_page_t* page,
int needed_height,
458static void pf_page_recompute_uvs(
pf_atlas_t* atlas,
size_t page_index);
461static int pf_atlas_alloc(
pf_atlas_t* atlas,
int w,
int h,
462 int* out_x,
int* out_y,
size_t* out_page);
468static uint32_t pf_utf8_decode(
const char** str);
471static void pf_walk_text(
pf_face_t* face,
const char* text,
476static bool pf_measure_cb(
const pf_quad_t* quad,
void* user);
482 PICO_FONT_ASSERT(page_width > 0);
483 PICO_FONT_ASSERT(max_page_height > 0);
490 atlas->page_width = page_width;
491 atlas->max_page_height = max_page_height;
493 atlas->cache_size = PICO_FONT_CACHE_INIT_SIZE;
494 atlas->cache = (pf_cache_entry_t*)PICO_FONT_CALLOC(atlas->cache_size,
495 sizeof(pf_cache_entry_t));
499 PICO_FONT_FREE(atlas);
504 if (pf_atlas_add_page(atlas) == PICO_FONT_ERROR)
506 PICO_FONT_FREE(atlas->cache);
507 PICO_FONT_FREE(atlas);
519 for (
size_t i = 0; i < atlas->page_count; i++)
521 PICO_FONT_FREE(atlas->pages[i].pixels);
524 PICO_FONT_FREE(atlas->pages);
525 PICO_FONT_FREE(atlas->glyphs);
526 PICO_FONT_FREE(atlas->cache);
527 PICO_FONT_FREE(atlas);
531 const unsigned char* ttf_data,
532 size_t ttf_data_size,
535 PICO_FONT_ASSERT(atlas != NULL);
536 PICO_FONT_ASSERT(ttf_data != NULL);
537 PICO_FONT_ASSERT(pixel_height > 0.0f);
546 face->ttf_data = (
unsigned char*)PICO_FONT_MALLOC(ttf_data_size);
550 PICO_FONT_FREE(face);
554 PICO_FONT_MEMCPY(face->ttf_data, ttf_data, ttf_data_size);
557 face->size = pixel_height;
559 int offset = stbtt_GetFontOffsetForIndex(ttf_data, 0);
562 PICO_FONT_FREE(face);
566 if (!stbtt_InitFont(&face->info, ttf_data, offset))
568 PICO_FONT_FREE(face);
572 face->scale = stbtt_ScaleForPixelHeight(&face->info, pixel_height);
574 int ascent, descent, gap;
575 stbtt_GetFontVMetrics(&face->info, &ascent, &descent, &gap);
576 face->ascent = (int)(ascent * face->scale + 0.5f);
577 face->descent = (int)(descent * face->scale - 0.5f);
578 face->line_gap = (int)(gap * face->scale + 0.5f);
586 PICO_FONT_FREE(face->ttf_data);
587 PICO_FONT_FREE(face);
592 PICO_FONT_ASSERT(face != NULL);
595 uint32_t key = pf_hash_key(codepoint, face->size);
598 size_t cached = pf_cache_lookup(atlas, key);
599 if (cached != PICO_FONT_ERROR)
604 if (glyph->
codepoint == codepoint && glyph->
size == face->size)
617 int glyph_index = stbtt_FindGlyphIndex(&face->info, (
int)codepoint);
619 int advance_raw, lsb;
620 stbtt_GetGlyphHMetrics(&face->info, glyph_index, &advance_raw, &lsb);
624 glyph.
size = face->size;
626 glyph.
advance_x = advance_raw * face->scale;
629 if (stbtt_IsGlyphEmpty(&face->info, glyph_index))
634 size_t index = pf_glyph_push(atlas, &glyph);
635 if (index == PICO_FONT_ERROR)
638 pf_cache_insert(atlas, key, index);
639 return &atlas->glyphs[index];
643 stbtt_GetGlyphBitmapBox(&face->info, glyph_index,
644 face->scale, face->scale,
649 if (bw <= 0 || bh <= 0)
651 size_t index = pf_glyph_push(atlas, &glyph);
653 if (index == PICO_FONT_ERROR)
656 pf_cache_insert(atlas, key, index);
657 return &atlas->glyphs[index];
663 if (pf_atlas_alloc(atlas, bw, bh, &ax, &ay, &ap) != 0)
669 pf_atlas_page_t* page = &atlas->pages[ap];
670 stbtt_MakeGlyphBitmap(&face->info,
671 page->pixels + ay * page->width + ax,
673 face->scale, face->scale,
685 float inv_w = 1.0f / (float)page->width;
686 float inv_h = 1.0f / (float)page->height;
688 glyph.
u0 = (float)ax * inv_w;
689 glyph.
v0 = (float)ay * inv_h;
690 glyph.
u1 = (float)(ax + bw) * inv_w;
691 glyph.
v1 = (float)(ay + bh) * inv_h;
693 size_t index = pf_glyph_push(atlas, &glyph);
695 if (index == PICO_FONT_ERROR)
698 pf_cache_insert(atlas, key, index);
699 return &atlas->glyphs[index];
706 PICO_FONT_ASSERT(face != NULL);
707 PICO_FONT_ASSERT(x != NULL);
708 PICO_FONT_ASSERT(y != NULL);
713 pf_walk_text(face, text, x, y, cb, user);
721 for (
size_t i = 0; i < atlas->page_count; i++)
723 pf_atlas_page_t* page = &atlas->pages[i];
728 if (!cb(i, page->pixels, page->width, page->height, user))
738 float* out_width,
float* out_height)
740 PICO_FONT_ASSERT(face != NULL);
754 pf_measure_state_t state = { 0, 0 };
755 pf_walk_text(face, text, &x, &y, pf_measure_cb, &state);
761 float line_height = (float)(face->ascent - face->descent + face->line_gap);
764 *out_width = state.max_x;
767 *out_height = (state.max_x > 0) ? line_height : 0;
772 PICO_FONT_ASSERT(face != NULL);
773 PICO_FONT_ASSERT(metrics != NULL);
775 metrics->
ascent = (float)face->ascent;
776 metrics->descent = (float)face->descent;
777 metrics->line_gap = (float)face->line_gap;
778 metrics->line_height = (float)(face->ascent - face->descent + face->line_gap);
783 PICO_FONT_ASSERT(face != NULL);
785 int g1 = stbtt_FindGlyphIndex(&face->info, (
int)cp1);
786 int g2 = stbtt_FindGlyphIndex(&face->info, (
int)cp2);
788 return stbtt_GetGlyphKernAdvance(&face->info, g1, g2) * face->scale;
793static uint32_t pf_hash_key(uint32_t cp,
float size)
795 uint32_t x = cp ^ (uint32_t)(size * 100.f);
796 x = ((x >> 16) ^ x) * 0x45d9f3b;
797 x = ((x >> 16) ^ x) * 0x45d9f3b;
802static size_t pf_cache_lookup(
const pf_atlas_t* atlas, uint32_t key)
804 size_t mask = atlas->cache_size - 1;
805 size_t index = (size_t)(key) & mask;
807 for (
size_t i = 0; i < atlas->cache_size; i++)
809 size_t slot = (index + i) & mask;
811 if (atlas->cache[slot].key == key)
812 return atlas->cache[slot].glyph_index;
814 if (atlas->cache[slot].key == 0)
815 return PICO_FONT_ERROR;
818 return PICO_FONT_ERROR;
821static void pf_cache_insert_raw(pf_cache_entry_t* cache,
size_t cache_size,
822 uint32_t key,
size_t glyph_index)
824 PICO_FONT_ASSERT(key != 0);
826 size_t mask = cache_size - 1;
827 size_t index = (size_t)(key) & mask;
829 for (
size_t i = 0; i < cache_size; i++)
831 size_t slot = (index + i) & mask;
833 if (cache[slot].key == 0)
835 cache[slot].key = key;
836 cache[slot].glyph_index = glyph_index;
841 PICO_FONT_ASSERT(
false);
844static int pf_cache_insert(
pf_atlas_t* atlas, uint32_t key,
size_t glyph_index)
847 size_t used = atlas->glyph_count;
849 if (used * 10 > atlas->cache_size * 7)
851 size_t new_size = atlas->cache_size * 2;
853 pf_cache_entry_t* new_cache = (pf_cache_entry_t*)PICO_FONT_CALLOC(new_size,
854 sizeof(pf_cache_entry_t));
860 for (
size_t i = 0; i < atlas->cache_size; i++)
862 if (atlas->cache[i].key != 0)
864 pf_cache_insert_raw(new_cache, new_size,
866 atlas->cache[i].glyph_index);
870 PICO_FONT_FREE(atlas->cache);
872 atlas->cache = new_cache;
873 atlas->cache_size = new_size;
876 pf_cache_insert_raw(atlas->cache, atlas->cache_size, key, glyph_index);
882static size_t pf_atlas_add_page(
pf_atlas_t* atlas)
884 if (atlas->page_count >= atlas->page_capacity)
886 size_t new_capacity = atlas->page_capacity ? atlas->page_capacity * 2 : 4;
888 pf_atlas_page_t* new_array = (pf_atlas_page_t*)PICO_FONT_REALLOC(atlas->pages,
889 new_capacity *
sizeof(pf_atlas_page_t));
892 return PICO_FONT_ERROR;
894 atlas->pages = new_array;
895 atlas->page_capacity = new_capacity;
898 size_t index = atlas->page_count;
900 pf_atlas_page_t* page = &atlas->pages[index];
901 PICO_FONT_MEMSET(page, 0,
sizeof(*page));
902 page->width = atlas->page_width;
905 if (pf_page_grow(page, PICO_FONT_INIT_PAGE_HEIGHT,
906 atlas->max_page_height) != 0)
908 return PICO_FONT_ERROR;
917static int pf_page_alloc(pf_atlas_page_t* page,
int w,
int h,
918 int* out_x,
int* out_y)
920 int pad = PICO_FONT_GLYPH_PADDING;
925 if (page->shelf.cursor_x + pw <= page->width &&
926 page->shelf.cursor_y + ph <= page->height)
928 if (ph > page->shelf.shelf_height)
929 page->shelf.shelf_height = ph;
931 *out_x = page->shelf.cursor_x;
932 *out_y = page->shelf.cursor_y;
933 page->shelf.cursor_x += pw;
939 page->shelf.cursor_x = 0;
940 page->shelf.cursor_y += page->shelf.shelf_height;
941 page->shelf.shelf_height = 0;
943 if (page->shelf.cursor_x + pw <= page->width &&
944 page->shelf.cursor_y + ph <= page->height)
946 page->shelf.shelf_height = ph;
948 *out_x = page->shelf.cursor_x;
949 *out_y = page->shelf.cursor_y;
950 page->shelf.cursor_x += pw;
963static int pf_page_grow(pf_atlas_page_t* page,
int needed_height,
int max_height)
965 PICO_FONT_ASSERT(page != NULL);
966 PICO_FONT_ASSERT(max_height > 0);
968 if (needed_height <= page->height)
971 if (needed_height > max_height)
974 int new_height = page->height > 0 ? page->height : 1;
975 while (new_height < needed_height)
980 if (new_height > max_height)
981 new_height = max_height;
983 unsigned char* new_pixels = (
unsigned char*)PICO_FONT_REALLOC(page->pixels,
984 (
size_t)page->width * (size_t)new_height);
990 PICO_FONT_MEMSET(new_pixels + (
size_t)page->width * (
size_t)page->height, 0,
991 (
size_t)page->width *
992 (
size_t)(new_height - page->height));
994 page->pixels = new_pixels;
995 page->height = new_height;
1002static void pf_page_recompute_uvs(
pf_atlas_t* atlas,
size_t page_index)
1004 PICO_FONT_ASSERT(page_index < atlas->page_count);
1005 PICO_FONT_ASSERT(atlas->pages[page_index].height > 0);
1007 float inv_h = 1.0f / (float)atlas->pages[page_index].height;
1009 for (
size_t i = 0; i < atlas->glyph_count; i++)
1013 if (g->
page != page_index)
1026static int pf_atlas_alloc(
pf_atlas_t* atlas,
int w,
int h,
1027 int* out_x,
int* out_y,
size_t* out_page)
1029 int pad = PICO_FONT_GLYPH_PADDING;
1033 if (atlas->page_count > 0)
1035 size_t page_index = atlas->page_count - 1;
1036 pf_atlas_page_t* page = &atlas->pages[page_index];
1038 if (pf_page_alloc(page, w, h, out_x, out_y) == 0)
1040 *out_page = page_index;
1045 int needed = page->shelf.cursor_y + page->shelf.shelf_height + ph;
1047 if (pf_page_grow(page, needed, atlas->max_page_height) == 0)
1049 pf_page_recompute_uvs(atlas, page_index);
1051 if (pf_page_alloc(page, w, h, out_x, out_y) == 0)
1053 *out_page = page_index;
1060 size_t page_index = pf_atlas_add_page(atlas);
1062 if (page_index == PICO_FONT_ERROR)
1066 pf_atlas_page_t* page = &atlas->pages[page_index];
1067 if (pf_page_grow(page, ph, atlas->max_page_height) != 0)
1072 if (pf_page_alloc(page, w, h, out_x, out_y) == 0)
1074 *out_page = page_index;
1084 if (atlas->glyph_count >= atlas->glyph_capacity)
1086 size_t new_capacity = atlas->glyph_capacity ? atlas->glyph_capacity * 2 : 64;
1092 return PICO_FONT_ERROR;
1094 atlas->glyphs = new_array;
1095 atlas->glyph_capacity = new_capacity;
1098 size_t index = atlas->glyph_count++;
1099 atlas->glyphs[index] = *glyph;
1105static uint32_t pf_utf8_decode(
const char** str)
1107 const unsigned char* s = (
const unsigned char*)*str;
1111 if (s[0] < 0x80) { cp = s[0]; n = 1; }
1112 else if (s[0] < 0xC0) { cp = 0xFFFD; n = 1; }
1113 else if (s[0] < 0xE0) { cp = s[0] & 0x1F; n = 2; }
1114 else if (s[0] < 0xF0) { cp = s[0] & 0x0F; n = 3; }
1115 else if (s[0] < 0xF8) { cp = s[0] & 0x07; n = 4; }
1116 else { cp = 0xFFFD; n = 1; }
1118 for (
int i = 1; i < n; i++)
1120 if ((s[i] & 0xC0) != 0x80)
1122 *str = (
const char*)(s + i);
1125 cp = (cp << 6) | (s[i] & 0x3F);
1129 if ((n == 2 && cp < 0x80) ||
1130 (n == 3 && cp < 0x800) ||
1131 (n == 4 && cp < 0x10000) ||
1132 (cp >= 0xD800 && cp <= 0xDFFF) ||
1138 *str = (
const char*)(s + n);
1144static void pf_walk_text(
pf_face_t* face,
const char* text,
1148 const char* s = text;
1149 uint32_t prev_cp = 0;
1153 uint32_t cp = pf_utf8_decode(&s);
1174 q.y0 = *y + (float)g->
offset_y + (
float)face->ascent;
1175 q.x1 = q.x0 + (float)g->
page_w;
1176 q.y1 = q.y0 + (float)g->
page_h;
1192static bool pf_measure_cb(
const pf_quad_t* quad,
void* user)
1194 pf_measure_state_t* st = (pf_measure_state_t*)user;
1196 if (quad->
x1 > st->max_x)
1197 st->max_x = quad->
x1;
1199 if (quad->
y1 > st->max_y)
1200 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
Opaque atlas handle.
Definition pico_font.h:106
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:175
struct pf_face_t pf_face_t
Opaque font-face handle.
Definition pico_font.h:111
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 and frees the TTF data it owns.
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:162
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.
pf_face_t * pf_create_face(pf_atlas_t *atlas, const unsigned char *ttf_data, size_t ttf_data_size, float pixel_height)
Create a font face at a given pixel height.
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.
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:117
float advance_x
Horizontal advance in pixels (scaled)
Definition pico_font.h:129
int offset_x
Definition pico_font.h:127
int glyph_index
stbtt glyph index (0 = missing glyph)
Definition pico_font.h:120
uint32_t codepoint
Unicode codepoint.
Definition pico_font.h:118
float v1
UV corners (computed after placement)
Definition pico_font.h:131
int page_h
Dimensions inside page (pixels)
Definition pico_font.h:123
int page_x
Definition pico_font.h:122
size_t page
Atlas page index.
Definition pico_font.h:125
float size
Font pixel height used when rasterizing.
Definition pico_font.h:119
int page_w
Definition pico_font.h:123
int offset_y
Offset from cursor to top-left of bitmap.
Definition pico_font.h:127
float v0
Definition pico_font.h:131
float u1
Definition pico_font.h:131
float u0
Definition pico_font.h:131
int page_y
Position inside page (pixels)
Definition pico_font.h:122
Vertical font metrics for a face.
Definition pico_font.h:148
float ascent
Distance from baseline to top of tallest glyph.
Definition pico_font.h:149
float line_gap
Extra spacing between lines.
Definition pico_font.h:151
float descent
Distance from baseline to bottom (typically negative).
Definition pico_font.h:150
float line_height
Recommended line advance (ascent - descent + line_gap).
Definition pico_font.h:152
Quad emitted by pf_draw_text.
Definition pico_font.h:138
float u0
Definition pico_font.h:140
size_t page
Atlas page index.
Definition pico_font.h:141
float x1
Definition pico_font.h:139
float y1
Screen-space rectangle.
Definition pico_font.h:139
float x0
Definition pico_font.h:139