summaryrefslogtreecommitdiff
path: root/src/text.cc
blob: fc67626c73637266402299c98b31fd2a436614d5 (plain)
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
#include "text.h"

#include <fcntl.h>
#include <mimalloc.h>
#include <unistd.h>
#include <utils.h>

#include "cglm/ivec2.h"
#include "freetype/freetype.h"
#include "hash.h"
#include "rendering.h"
#include "utils.h"

static bool wayc_font_cache_lookup(struct font_s* font, codepoint_t codepoint,
                                   struct glyph_s* out) {
  struct glyph_s glyph;
  bool ok = wayc_hashmap_get(&font->cache, &codepoint, &glyph);
  if (ok) *out = glyph;
  return ok;
}

[[maybe_unused]] static void wayc_font_cache_insert(struct font_s* font,
                                                    codepoint_t codepoint,
                                                    struct glyph_s glyph) {
  wayc_notnull(font);
  wayc_hashmap_insert(&font->cache, &codepoint, &glyph);
}

enum font_context_error_e wayc_font_context_init(struct font_context_s* ctx) {
  wayc_notnull(ctx);

  FT_Error err = FT_Init_FreeType(&ctx->library);
  if (err) return FONT_CONTEXT_ERROR_LIBRARY;
  return FONT_CONTEXT_ERROR_NONE;
}

void wayc_font_context_deinit(struct font_context_s* ctx) {
  wayc_notnull(ctx);

  FT_Done_FreeType(ctx->library);
}

enum font_error_e wayc_font_init(struct font_s* font,
                                 struct font_context_s* ctx, u32 fsize,
                                 const char* path) {
  wayc_notnull(font);
  wayc_notnull(ctx);
  wayc_notnull(path);

  bool success = false;

  i32 fd = open(path, O_RDONLY);
  if (fd < 0) return FONT_ERROR_FILE_LOAD;
  wayc_defer(close(fd));

  isize size = lseek(fd, 0, SEEK_END);
  if (size < 0) return FONT_ERROR_FILE_LOAD;
  lseek(fd, 0, SEEK_SET);

  u8* data = (u8*)mi_malloc(size);
  wayc_defer_cond({ mi_free(data); }, success, true);

  isize _read = read(fd, data, size);
  if (_read < 0 || _read != size) return FONT_ERROR_FILE_LOAD;

  FT_Error err = FT_New_Memory_Face(ctx->library, data, size, 0, &font->face);
  if (err) return FONT_ERROR_FONT_LOAD;
  wayc_defer_cond(FT_Done_Face(font->face);, success, true);

  err = FT_Set_Pixel_Sizes(font->face, 0, fsize);
  if (err) return FONT_ERROR_FONT_LOAD;

  font->data = data;
  wayc_hashmap_init(&font->cache);
  glm_ivec2_zero(font->cursor);

  success = true;
  return FONT_ERROR_NONE;
}

enum font_error_e wayc_font_lookup(struct font_s* font, struct atlas_s* atlas,
                                   codepoint_t codepoint, struct glyph_s* out) {
  wayc_notnull(font);
  wayc_notnull(out);

  FT_Face face = font->face;

  bool found = wayc_font_cache_lookup(font, codepoint, out);
  if (found) return FONT_ERROR_NONE;

  FT_UInt glyph_index = FT_Get_Char_Index(face, codepoint);
  if (glyph_index == 0) return FONT_ERROR_NOT_MATCH;

  FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
  FT_GlyphSlot slot = face->glyph;
  FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);

  FT_Bitmap bitmap = slot->bitmap;
  ivec2 size = {(i32)bitmap.width, (i32)bitmap.rows};

  wayc_atlas_set(atlas, IMAGE_DATA_TYPE_UNSIGNED_BYTE, font->cursor, size[0],
                 size[1], bitmap.buffer);

  struct glyph_s glyph = {};
  glm_ivec2(font->cursor, glyph.uv0);
  glm_ivec2_add(glyph.uv0, size, glyph.uv1);

  wayc_font_cache_insert(font, codepoint, glyph);
  glm_ivec2_add(font->cursor, size, font->cursor);

  *out = glyph;
  return FONT_ERROR_NONE;
}

void wayc_font_deinit(struct font_s* font) {
  wayc_notnull(font);

  wayc_hashmap_deinit(&font->cache);
  FT_Done_Face(font->face);
  mi_free(font->data);
}