Commit 3585e8946d4b7bd0e76a3eb67bacd7b41a6f0624

Thomas de Grivel 2024-02-24T15:53:37

vtext_render_to_texture_random

diff --git a/libc3/window/sdl2/demo/matrix_utf8.c b/libc3/window/sdl2/demo/matrix_utf8.c
index b38ce5d..5b46fd1 100644
--- a/libc3/window/sdl2/demo/matrix_utf8.c
+++ b/libc3/window/sdl2/demo/matrix_utf8.c
@@ -70,42 +70,22 @@ bool matrix_utf8_text_init (s_tag *tag, f32 y)
 {
   char a[1024];
   s_buf buf;
-  character c;
-  FT_Face face;
   u8 i;
   u8 len;
   s_map *map;
   f32 spacing;
-  s_str str;
   s_gl_text *text;
   if (! tag_map(tag, 3))
     return false;
   buf_init(&buf, false, sizeof(a), a);
-  u8_random_uniform(&len, 40);
-  len += 10;
-  face = g_matrix_utf8_font.ft_face;
-  i = 0;
-  while (i < len) {
-    do {
-      u32_random(&c);
-    } while (! FT_Get_Char_Index(face, c));
-    if (buf_write_character_utf8(&buf, c) < 0) {
-      err_puts("matrix_utf8_init_text: buffer overflow");
-      assert(! "matrix_utf8_init_text: buffer overflow");
-      return false;
-    }
-    i++;
-  }
-  buf_read_to_str(&buf, &str);
-  u8_random_uniform(&i, 15);
+  u8_random_uniform(&i, 10);
   spacing = i * G_MATRIX_UTF8_FONT_SIZE;
-  text = gl_vtext_new_str(&g_matrix_utf8_font, &str);
-  if (! text)
+  u8_random_uniform(&len, 10);
+  len += 10;
+  text = gl_vtext_new(&g_matrix_utf8_font);
+  if (! text ||
+      ! gl_vtext_render_to_texture_random(text, len))
     return false;
-  gl_vtext_update(text);
-  err_inspect_str(&str);
-  err_write_1("\n");
-  str_clean(&str);
   map = &tag->data.map;
   tag_init_sym(  map->key + 0, sym_1("spacing"));
   tag_init_f32(map->value + 0, spacing);
diff --git a/libc3/window/sdl2/gl_vtext.c b/libc3/window/sdl2/gl_vtext.c
index 2d9472a..dd3aaa0 100644
--- a/libc3/window/sdl2/gl_vtext.c
+++ b/libc3/window/sdl2/gl_vtext.c
@@ -57,6 +57,22 @@ s_gl_text * gl_vtext_init_str (s_gl_text *text, const s_gl_font *font,
   return text;
 }
 
+s_gl_text * gl_vtext_new (const s_gl_font *font)
+{
+  s_gl_text *text;
+  text = calloc(1, sizeof(s_gl_text));
+  if (! text) {
+    err_puts("gl_vtext_new: failed to allocate memory");
+    assert(! "gl_vtext_new: failed to allocate memory");
+    return NULL;
+  }
+  if (! gl_vtext_init(text, font)) {
+    free(text);
+    return NULL;
+  }
+  return text;
+}
+
 s_gl_text * gl_vtext_new_1 (const s_gl_font *font, const char *p)
 {
   s_gl_text *text;
@@ -190,6 +206,121 @@ bool gl_vtext_render_to_texture (s_gl_text *text)
   return true;
 }
 
+bool gl_vtext_render_to_texture_random (s_gl_text *text, uw len)
+{
+  FT_UInt *glyphs;
+  u8 *data;
+  uw  data_w;
+  uw  data_h;
+  u8 *data_pixel;
+  uw  data_size;
+  uw  data_x;
+  uw  data_y;
+  FT_Face face;
+  const s_gl_font *font;
+  FT_GlyphSlot glyph;
+  FT_UInt glyph_index;
+  uw i;
+  uw j;
+  uw k;
+  uw line_height;
+  uw max_ascent;
+  uw max_descent;
+  f32 scale_y;
+  uw x;
+  uw y;
+  assert(text);
+  assert(text->font);
+  assert(text->texture);
+  assert(glGetError() == GL_NO_ERROR);
+  glBindTexture(GL_TEXTURE_2D, text->texture);
+  assert(glGetError() == GL_NO_ERROR);
+  font = text->font;
+  face = font->ft_face;
+  glyphs = calloc(len, sizeof(FT_UInt));
+  if (! glyphs) {
+    err_puts("gl_vtext_render_to_texture_random:"
+             " failed to allocate memory");
+    assert(! "gl_vtext_render_to_texture_random:"
+             " failed to allocate memory");
+    return false;
+  }
+  for (i = 0; i < len; i++) {
+    do {
+      u32_random_uniform(glyphs + i, face->num_glyphs - 2);
+      glyphs[i]++;
+      if (FT_Load_Glyph(face, glyphs[i], FT_LOAD_RENDER))
+        continue;
+      glyph = face->glyph;
+      printf("width %ld\n", glyph->metrics.width);
+    } while (! glyph->metrics.width);
+  }
+  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;
+  line_height = max_ascent + max_descent;
+  data_w = 0;
+  data_h = 0;
+  x = 0;
+  for (i = 0; i < len; i++) {
+    glyph_index = glyphs[i];
+    if (FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER)) {
+      err_write_1("gl_vtext_render_to_texture_random: failed to load glyph: ");
+      err_inspect_u32(&glyph_index);
+      err_write_1("\n");
+      continue;
+    }
+    glyph = face->glyph;
+    x = glyph->metrics.horiAdvance >> 6;
+    if (x > data_w)
+      data_w = x;
+    data_h += line_height;
+  }
+  data_size = data_w * data_h * 4;
+  data = calloc(1, data_size);
+  x = 0;
+  y = 0;
+  for (i = 0; i < len; i++) {
+    glyph_index = glyphs[i];
+    if (FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER))
+      continue;
+    glyph = face->glyph;
+    x = (data_w - (glyph->metrics.width >> 6)) / 2;
+    j = 0;
+    while (j < glyph->bitmap.rows) {
+      data_y = data_h - 1 - (y + j + max_ascent - glyph->bitmap_top);
+      //printf("\n");
+      k = 0;
+      while (k < glyph->bitmap.width) {
+        data_x = x + k;
+        data_pixel = data + (data_y * data_w + data_x) * 4;
+        u8 value = glyph->bitmap.buffer[j * glyph->bitmap.width + k];
+        data_pixel[0] = 255;
+        data_pixel[1] = 255;
+        data_pixel[2] = 255;
+        data_pixel[3] = value;
+        //printf("%s", g_gray_3_bits_utf8[value / 32]);
+        k++;
+      }
+      j++;
+    }
+    y += line_height;
+  }
+  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, data_w, data_h, 0, GL_RGBA,
+               GL_UNSIGNED_BYTE, data);
+  assert(glGetError() == GL_NO_ERROR);
+  glGenerateMipmap(GL_TEXTURE_2D);
+  assert(glGetError() == GL_NO_ERROR);
+  free(data);
+  glBindTexture(GL_TEXTURE_2D, 0);
+  text->pix_w = data_w;
+  text->pix_h = data_h;
+  text->pt_w = text->pix_w * text->font->point_per_pixel;
+  text->pt_h = text->pix_h * text->font->point_per_pixel;
+  //printf("\n");
+  return true;
+}
+
 bool gl_vtext_set_font (s_gl_text *text, const s_gl_font *font)
 {
   assert(text);
diff --git a/libc3/window/sdl2/gl_vtext.h b/libc3/window/sdl2/gl_vtext.h
index 9018700..e23528f 100644
--- a/libc3/window/sdl2/gl_vtext.h
+++ b/libc3/window/sdl2/gl_vtext.h
@@ -26,11 +26,13 @@ s_gl_text * gl_vtext_init_str (s_gl_text *text, const s_gl_font *font,
 
 /* Heap-allocation functions, call gl_vtext_delete after use. */
 void        gl_vtext_delete (s_gl_text *text);
+s_gl_text * gl_vtext_new (const s_gl_font *font);
 s_gl_text * gl_vtext_new_1 (const s_gl_font *font, const char *p);
 s_gl_text * gl_vtext_new_str (const s_gl_font *font, const s_str *str);
 
 /* Operators. */
 bool gl_vtext_render_to_texture (s_gl_text *text);
+bool gl_vtext_render_to_texture_random (s_gl_text *text, uw len);
 bool gl_vtext_set_font (s_gl_text *text, const s_gl_font *font);
 bool gl_vtext_set_text (s_gl_text *text, const s_str *str);
 bool gl_vtext_set_text_1 (s_gl_text *text, const char *p);