~vladh/peony

peony/src/fonts.cpp -rw-r--r-- 3.6 KiB
7fc9922bVlad-Stefan Harbuz changes shaders namespace into class a month ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
  Peony Game Engine
  Copyright (C) 2020 Vlad-Stefan Harbuz <vlad@vladh.net>
  All rights reserved.
*/

#include "../src_external/glad/glad.h"
#include "../src_external/pstr.h"
#include "logs.hpp"
#include "array.hpp"
#include "materials.hpp"
#include "fonts.hpp"
#include "intrinsics.hpp"


namespace fonts {
  pny_internal void load_glyphs(
    FontAsset *font_asset,
    FT_Face face,
    TextureAtlas *texture_atlas
  ) {
    FT_GlyphSlot glyph = face->glyph;

    // TODO: Can we avoid loading all characters twice here?
    for (uint32 c = 0; c < CHAR_MAX_CODEPOINT_TO_LOAD; c++) {
      Character *character = font_asset->characters.push();

      if (FT_Load_Char(face, c, FT_LOAD_RENDER)) {
        logs::error("Failed to load glyph %s", c);
        continue;
      }

      character->size = iv2(glyph->bitmap.width, glyph->bitmap.rows);
      character->bearing = iv2(glyph->bitmap_left, glyph->bitmap_top);
      character->advance = iv2(glyph->advance.x, glyph->advance.y);
    }

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture_atlas->texture_name);

    for (uint32 c = 0; c < CHAR_MAX_CODEPOINT_TO_LOAD; c++) {
      if (
        // Unicode C0 controls
        (c <= 0x1F) ||
        // DEL
        (c == 0x7F) ||
        // Unicode C1 controls
        (c >= 0x80 && c <= 0x9F)
      ) {
        continue;
      }

      Character *character = font_asset->characters[c];

      iv2 tex_coords = materials::push_space_to_texture_atlas(
        texture_atlas, character->size
      );

      if (FT_Load_Char(face, c, FT_LOAD_RENDER)) {
        logs::error("Failed to load glyph %s", c);
        continue;
      }

      glTexSubImage2D(
        GL_TEXTURE_2D, 0, tex_coords.x, tex_coords.y,
        character->size.x, character->size.y,
        GL_RED, GL_UNSIGNED_BYTE, glyph->bitmap.buffer
      );

      character->tex_coords = tex_coords;
    }

    glBindTexture(GL_TEXTURE_2D, 0);
  }
}


real32 fonts::frac_px_to_px(uint32 n) {
  return (real32)(n >> 6);
}


real32 fonts::font_unit_to_px(uint32 n) {
  // NOTE: We should be dividing by units_per_em here...probably?
  // This is because we expect height etc. to be in "font units".
  // But treating these metrics as "fractional pixels" seems to work,
  // whereas division by units_per_em doesn't.
  // Check this in more detail.
  return (real32)(n >> 6);
}


FontAsset* fonts::get_by_name(Array<FontAsset> *assets, const char *name) {
  each (asset, *assets) {
    if (pstr_eq(asset->name, name)) {
      return asset;
    }
  }
  logs::warning("Could not find FontAsset with name %s", name);
  return nullptr;
}


FontAsset* fonts::init_font_asset(
  FontAsset *font_asset,
  MemoryPool *memory_pool,
  TextureAtlas *texture_atlas,
  FT_Library *ft_library,
  const char *name,
  const char *filename,
  uint16 font_size
) {
  font_asset->name = name;
  font_asset->font_size = font_size;

  char path[MAX_PATH];
  strcpy(path, FONTS_DIR);
  strcat(path, filename);

  font_asset->characters = Array<Character>(
    memory_pool,
    CHAR_MAX_CODEPOINT_TO_LOAD + 1,
    "characters"
  );

  FT_Face face;
  if (FT_New_Face(*ft_library, path, 0, &face)) {
    logs::error("Could not load font at %s", path);
  }
  FT_Set_Pixel_Sizes(face, 0, font_asset->font_size);
  if (!FT_IS_SCALABLE(face)) {
    logs::fatal("Font face not scalable, don't know what to do.");
  }
  font_asset->units_per_em = face->units_per_EM;
  font_asset->ascender = face->ascender;
  font_asset->descender = face->descender;
  font_asset->height = face->height;

  load_glyphs(font_asset, face, texture_atlas);

  FT_Done_Face(face);

  return font_asset;
}