Commit e64a3d358fbf7c1c5deaf4e0336c4bca8451d7bd

Thomas de Grivel 2024-01-28T21:32:52

fixed horizontal advance and vertical baseline alignment for gl_text

diff --git a/libc3/window/sdl2/gl_text.c b/libc3/window/sdl2/gl_text.c
index 7b1dd2a..2f0f92f 100644
--- a/libc3/window/sdl2/gl_text.c
+++ b/libc3/window/sdl2/gl_text.c
@@ -65,15 +65,18 @@ bool gl_text_render_to_texture (s_gl_text *text)
   uw  data_x;
   uw  data_y;
   FT_Vector delta;
+  FT_Face face;
   const s_gl_font *font;
   FT_GlyphSlot glyph;
   FT_UInt glyph_index;
   uw i;
   uw j;
-  f32 max_height = 0.0;
+  uw max_ascent;
+  uw max_descent;
   FT_UInt prev_glyph_index = 0;
   s_str s;
-  f32 total_width = 0.0;
+  f32 scale_y;
+  f32 x;
   assert(text);
   assert(text->font);
   assert(text->texture);
@@ -83,50 +86,49 @@ bool gl_text_render_to_texture (s_gl_text *text)
   glBindTexture(GL_TEXTURE_2D, text->texture);
   assert(glGetError() == GL_NO_ERROR);
   font = text->font;
+  face = font->ft_face;
   s = text->str;
+  scale_y = face->size->metrics.y_scale / 65536.0;
+  max_ascent = (u32) (face->ascender * scale_y) >> 6;
+  max_descent = (u32) abs((int) (face->descender * scale_y)) >> 6;
+  data_w = 0;
+  data_h = max_ascent + max_descent;
   while (str_read_character_utf8(&s, &c) > 0) {
-    glyph_index = FT_Get_Char_Index(font->ft_face, c);
+    glyph_index = FT_Get_Char_Index(face, c);
     if (prev_glyph_index && glyph_index) {
-      FT_Get_Kerning(font->ft_face, prev_glyph_index, glyph_index,
+      FT_Get_Kerning(face, prev_glyph_index, glyph_index,
                      FT_KERNING_DEFAULT, &delta);
-      total_width += delta.x >> 6;
+      data_w += delta.x >> 6;
     }
-    if (FT_Load_Glyph(font->ft_face, glyph_index, FT_LOAD_RENDER)) {
+    if (FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER)) {
       err_write_1("gl_font_render_to_texture: failed to load glyph: ");
       err_inspect_character(&c);
       err_write_1("\n");
       continue;
     }
-    glyph = font->ft_face->glyph;
-    total_width += glyph->bitmap.width;
-    if (glyph->bitmap.rows + glyph->bitmap_top > max_height)
-      max_height = glyph->bitmap.rows + glyph->bitmap_top;
+    glyph = face->glyph;
+    data_w += glyph->metrics.horiAdvance >> 6;
     prev_glyph_index = glyph_index;
   }
-  data_w = ceil(total_width);
-  data_h = ceil(max_height);
   data_size = data_w * data_h * 4;
   data = calloc(1, data_size);
-  f32 x = 0;
+  x = 0;
   prev_glyph_index = 0;
   s = text->str;
   while (str_read_character_utf8(&s, &c) > 0) {
-    glyph_index = FT_Get_Char_Index(font->ft_face, c);
-
-    // Apply kerning (adjust spacing between characters)
+    glyph_index = FT_Get_Char_Index(face, c);
     if (prev_glyph_index && glyph_index) {
       FT_Vector delta;
-      FT_Get_Kerning(font->ft_face, prev_glyph_index, glyph_index,
+      FT_Get_Kerning(face, prev_glyph_index, glyph_index,
                      FT_KERNING_DEFAULT, &delta);
       x += delta.x >> 6;
     }
-    if (FT_Load_Glyph(font->ft_face, glyph_index, FT_LOAD_RENDER)) {
+    if (FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER))
       continue;
-    }
-    glyph = font->ft_face->glyph;
+    glyph = face->glyph;
     i = 0;
     while (i < glyph->bitmap.rows) {
-      data_y = i + glyph->bitmap_top;
+      data_y = data_h - 1 - i - max_ascent + glyph->bitmap_top;
       //printf("\n");
       j = 0;
       while (j < glyph->bitmap.width) {
@@ -137,13 +139,13 @@ bool gl_text_render_to_texture (s_gl_text *text)
         data_pixel[0] = 255;
         data_pixel[1] = 255;
         data_pixel[2] = 255;
-        data_pixel[3] = (u8) value;
+        data_pixel[3] = value;
         //printf("%s", (const char *[]) {" ", ".", ":", "#", "░", "▒", "▓", "█"}[value / 32]);
         j++;
       }
       i++;
     }
-    x += glyph->bitmap.width;
+    x += glyph->metrics.horiAdvance >> 6;
     prev_glyph_index = glyph_index;
   }
   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, data_w, data_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);