util_font.c (2870B)
1 ////////////////////////////////////////////////////////////////// 2 // util_font.c 3 4 #define STB_RECT_PACK_IMPLEMENTATION 5 #include "../external/stb_rect_pack.h" 6 #define STB_TRUETYPE_IMPLEMENTATION 7 #include "../external/stb_truetype.h" 8 9 RV_GLOBAL rv_ascii_font_t* rv_ascii_font_from_file(rv_arena* arena, rv_str8 filename, s32 point_size) 10 { 11 rv_temp_arena scratch = rv_scratch_begin(0, 0); 12 rv_str8 f = rv_read_file(scratch.arena, filename); 13 rv_ascii_font_t* res = rv_ascii_font_from_memory(arena, f, point_size); 14 rv_scratch_end(scratch); 15 16 return res; 17 } 18 19 RV_GLOBAL rv_ascii_font_t* rv_ascii_font_from_memory(rv_arena* arena, rv_str8 ttf_data, s32 point_size) 20 { 21 // TODO(Samdal): make index choosable? 22 s32 index = 0; 23 24 rv_ascii_font_t* font = rv_push(arena, rv_ascii_font_t); 25 26 if (point_size < 0) { 27 rv_unreachable(); 28 point_size = 10; 29 } 30 font->point_size = point_size; 31 32 const int load_font = stbtt_InitFont(&font->info, ttf_data.str, stbtt_GetFontOffsetForIndex(ttf_data.str, index)); 33 rv_assert(load_font); 34 35 float s = stbtt_ScaleForPixelHeight(&font->info, point_size); 36 int a, d, l; 37 stbtt_GetFontVMetrics(&font->info, &a, &d, &l); 38 font->linedist = (a * s) - (d * s) + (l * s); 39 40 // Poor attempt at an auto resized texture 41 s32 w = (f32)point_size * sqrtf(RV_ASCII_FONT_GLYPH_COUNT) * sqrtf(0.45f); 42 s32 h = (f32)point_size * sqrtf(RV_ASCII_FONT_GLYPH_COUNT) * sqrtf(0.45f); 43 w = rv_align_pow2(w, 64); 44 h = rv_align_pow2(h, 64); 45 46 u8* bitmap = rv_arena_push(arena, w * h, 8); 47 48 stbtt_pack_context pc; 49 stbtt_PackBegin(&pc, bitmap, w, h, 0, 1, NULL); 50 stbtt_PackSetOversampling(&pc, 1, 1); 51 stbtt_PackFontRange(&pc, ttf_data.str, 0, point_size, 32, 96, font->cdata); 52 stbtt_PackEnd(&pc); 53 54 font->tex = rv_push_compound(arena, rv_texture_t, { 55 .data = bitmap, 56 .size = rv_v2(w, h), 57 .format = RV_TEXTURE_FORMAT_R8, 58 .min_filter = RV_TEXTURE_FILTER_LINEAR, 59 .mag_filter = RV_TEXTURE_FILTER_LINEAR, 60 }); 61 62 return font; 63 } 64 65 RV_GLOBAL rv_vec2 gs_asset_font_text_dimensions(rv_ascii_font_t* font, rv_str8 text) 66 { 67 rv_vec2 dimensions = {}; 68 69 s32 lines = 0; 70 f32 x = 0; 71 f32 yover = font->point_size; 72 f32 ybelow = 0; 73 74 for (s32 i = 0; i < RV_ASCII_FONT_GLYPH_COUNT; i++) { 75 ybelow = rv_max(ybelow, -font->cdata[i].yoff2); 76 } 77 78 for (s32 i = 0; i < text.len; i++) { 79 if (text.str[i] == '\n') { 80 lines++; 81 dimensions.x = rv_max(dimensions.x, x); 82 x = 0; 83 continue; 84 } 85 86 if (text.str[i] >= 32 && text.str[i] <= 127) { 87 x += font->cdata[text.str[i] - 32].xadvance; 88 } 89 }; 90 dimensions.y += (yover) * (lines+1) + ybelow; 91 dimensions.x = rv_max(dimensions.x, x); 92 93 return dimensions; 94 }