A 3D game engine from scratch.
at main 133 lines 3.5 kB view raw
1// (c) 2020 Vlad-Stefan Harbuz <vlad@vladh.net> 2 3#include "../src_external/glad/glad.h" 4#include "../src_external/pstr.h" 5#include "logs.hpp" 6#include "array.hpp" 7#include "mats.hpp" 8#include "fonts.hpp" 9#include "intrinsics.hpp" 10 11 12f32 13fonts::frac_px_to_px(u32 n) 14{ 15 return (f32)(n >> 6); 16} 17 18 19f32 20fonts::font_unit_to_px(u32 n) 21{ 22 // NOTE: We should be dividing by units_per_em here...probably? 23 // This is because we expect height etc. to be in "font units". 24 // But treating these metrics as "fractional pixels" seems to work, 25 // whereas division by units_per_em doesn't. 26 // Check this in more detail. 27 return (f32)(n >> 6); 28} 29 30 31fonts::FontAsset * 32fonts::get_by_name(Array<FontAsset> *assets, const char *name) 33{ 34 each (asset, *assets) { 35 if (pstr_eq(asset->name, name)) { 36 return asset; 37 } 38 } 39 logs::warning("Could not find FontAsset with name %s", name); 40 return nullptr; 41} 42 43 44fonts::FontAsset * 45fonts::init_font_asset( 46 FontAsset *font_asset, 47 memory::Pool *memory_pool, 48 mats::TextureAtlas *texture_atlas, 49 FT_Library *ft_library, 50 const char *name, 51 const char *filename, 52 u16 font_size 53) { 54 font_asset->name = name; 55 font_asset->font_size = font_size; 56 57 char path[MAX_PATH]; 58 strcpy(path, FONTS_DIR); 59 strcat(path, filename); 60 61 font_asset->characters = Array<Character>(memory_pool, CHAR_MAX_CODEPOINT_TO_LOAD + 1, "characters"); 62 63 FT_Face face; 64 if (FT_New_Face(*ft_library, path, 0, &face)) { 65 logs::error("Could not load font at %s", path); 66 } 67 FT_Set_Pixel_Sizes(face, 0, font_asset->font_size); 68 if (!FT_IS_SCALABLE(face)) { 69 logs::fatal("Font face not scalable, don't know what to do."); 70 } 71 font_asset->units_per_em = face->units_per_EM; 72 font_asset->ascender = face->ascender; 73 font_asset->descender = face->descender; 74 font_asset->height = face->height; 75 76 load_glyphs(font_asset, face, texture_atlas); 77 78 FT_Done_Face(face); 79 80 return font_asset; 81} 82 83 84void 85fonts::load_glyphs( 86 FontAsset *font_asset, 87 FT_Face face, 88 mats::TextureAtlas *texture_atlas 89) { 90 FT_GlyphSlot glyph = face->glyph; 91 92 // TODO: Can we avoid loading all characters twice here? 93 for (u32 c = 0; c < CHAR_MAX_CODEPOINT_TO_LOAD; c++) { 94 Character *character = font_asset->characters.push(); 95 96 if (FT_Load_Char(face, c, FT_LOAD_RENDER)) { 97 logs::error("Failed to load glyph %s", c); 98 continue; 99 } 100 101 character->size = iv2(glyph->bitmap.width, glyph->bitmap.rows); 102 character->bearing = iv2(glyph->bitmap_left, glyph->bitmap_top); 103 character->advance = iv2(glyph->advance.x, glyph->advance.y); 104 } 105 106 mats::activate_font_texture(texture_atlas->texture_name); 107 108 for (u32 c = 0; c < CHAR_MAX_CODEPOINT_TO_LOAD; c++) { 109 if ( 110 // Unicode C0 controls 111 (c <= 0x1F) || 112 // DEL 113 (c == 0x7F) || 114 // Unicode C1 controls 115 (c >= 0x80 && c <= 0x9F) 116 ) { 117 continue; 118 } 119 120 Character *character = font_asset->characters[c]; 121 122 iv2 tex_coords = mats::push_space_to_texture_atlas(texture_atlas, character->size); 123 124 if (FT_Load_Char(face, c, FT_LOAD_RENDER)) { 125 logs::error("Failed to load glyph %s", c); 126 continue; 127 } 128 129 mats::push_font_texture(tex_coords, character->size, glyph->bitmap.buffer); 130 131 character->tex_coords = tex_coords; 132 } 133}