Commit 0f51370066b949283f87d68aca98177270897753

Thomas de Grivel 2024-01-18T14:55:09

wip f128

diff --git a/libc3/array.c b/libc3/array.c
index fb06852..585b469 100644
--- a/libc3/array.c
+++ b/libc3/array.c
@@ -150,6 +150,16 @@ s_tag * array_data_tag (const s_tag *a, const s_tag *address,
   return dest;
 }
 
+s_array * array_free (s_array *a)
+{
+  a->data = NULL;
+  if (a->free_data) {
+    free(a->free_data);
+    a->free_data = NULL;
+  }
+  return a;
+}
+
 s_array * array_init (s_array *a, const s_sym *type, uw dimension,
                       const uw *dimensions)
 {
@@ -160,8 +170,6 @@ s_array * array_init (s_array *a, const s_sym *type, uw dimension,
   assert(a);
   assert(type);
   assert(sym_is_module(type));
-  assert(dimension);
-  assert(dimensions);
   tmp.type = type;
   if (dimension) {
 #ifdef DEBUG
diff --git a/libc3/array.h b/libc3/array.h
index 254f32e..832ba59 100644
--- a/libc3/array.h
+++ b/libc3/array.h
@@ -34,5 +34,6 @@ s_tag *            array_data_tag (const s_tag *a, const s_tag *address,
 s_array * array_allocate (s_array *a);
 s_array * array_data_set (s_array *a, const uw *address,
                           const void *data);
+s_array * array_free (s_array *a);
 
 #endif /* LIBC3_ARRAY_H */
diff --git a/libc3/buf_inspect.c b/libc3/buf_inspect.c
index 989e84c..880367c 100644
--- a/libc3/buf_inspect.c
+++ b/libc3/buf_inspect.c
@@ -803,7 +803,7 @@ sw buf_inspect_f128 (s_buf *buf, const f128 *x)
   sw result = 0;
   f128 y;
   assert(buf);
-  assert(f);
+  assert(x);
   exp = 0.0;
   y = *x;
   if (y == 0.0)
diff --git a/libc3/f128.c b/libc3/f128.c
index f5e7377..d7f77fe 100644
--- a/libc3/f128.c
+++ b/libc3/f128.c
@@ -12,6 +12,7 @@
  */
 #include <assert.h>
 #include <err.h>
+#include <math.h>
 #include <stdlib.h>
 #include "integer.h"
 #include "tag.h"
@@ -89,12 +90,22 @@ f128 * f128_init_copy (f128 *x, const f128 *src)
   return x;
 }
 
+typedef union _128 {
+  f128 f128;
+  s128 s128;
+  u128 u128;
+  u64 u64[2];
+  s64 s64[2];
+} u_128;
+
 f128 * f128_random (f128 *x)
 {
-  const f128 max = exp2l(113) - 1;
-  f128 y;
-  arc4random_buf(y, 15);
-  y = (f128) ((u128) y & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFF800000);
-  *x = y;
+  u_128 u;
+  u_128 mask;
+  arc4random_buf(&u, 15);
+  mask.u64[0] = 0x7FFFFFFFFFFFFFFF;
+  mask.u64[1] = 0xFFFFFFFFFFFFC000;
+  u.u128 &= mask.u128;
+  *x = u.f128;
   return x;
 }
diff --git a/libc3/window/sdl2/demo/mandelbrot_f128.c b/libc3/window/sdl2/demo/mandelbrot_f128.c
index e99d6bf..9a160b8 100644
--- a/libc3/window/sdl2/demo/mandelbrot_f128.c
+++ b/libc3/window/sdl2/demo/mandelbrot_f128.c
@@ -12,28 +12,44 @@
  */
 #include <math.h>
 #include <libc3/c3.h>
-#include "../types.h"
+#include "../gl_deprecated.h"
+#include "../gl_matrix_4f.h"
+#include "../gl_ortho.h"
 #include "mandelbrot_f128.h"
+#include "window_sdl2_demo.h"
+
+// FIXME: move g_mandelbrot_f128_texture to seq->tag
+static GLuint g_mandelbrot_f128_texture = 0;
+
+static bool mandelbrot_f128_resize (s_sequence *seq);
+static bool mandelbrot_f128_update (s_sequence *seq);
 
 bool mandelbrot_f128_load (s_sequence *seq)
 {
   s_map *map;
   assert(seq);
-  if (! tag_map(&seq->tag, 5))
+  if (! tag_map(&seq->tag, 9))
     return false;
   map = &seq->tag.data.map;
-  tag_init_sym(   map->key + 0, sym_1("h"));
-  tag_init_uw(  map->value + 0, 0);
-  tag_init_sym(   map->key + 1, sym_1("pixels"));
-  tag_init_uw(  map->value + 1, 0);
-  tag_init_sym(   map->key + 2, sym_1("w"));
-  tag_init_uw(  map->value + 2, 0);
-  tag_init_sym(   map->key + 3, sym_1("x"));
-  tag_init_f128(map->value + 3, 0.0);
-  tag_init_sym(   map->key + 4, sym_1("y"));
-  tag_init_f128(map->value + 4, 0.0);
-  tag_init_sym(   map->key + 5, sym_1("z"));
-  tag_init_f128(map->value + 5, 0.01);
+  tag_init_sym(    map->key + 0, sym_1("h"));
+  tag_init_uw(   map->value + 0, 0);
+  tag_init_sym(    map->key + 1, sym_1("next_x"));
+  tag_init_f128( map->value + 1, 0.0);
+  tag_init_sym(    map->key + 2, sym_1("next_y"));
+  tag_init_f128( map->value + 2, 0.0);
+  tag_init_sym(    map->key + 3, sym_1("next_z"));
+  tag_init_f128( map->value + 3, 0.01);
+  tag_init_sym(    map->key + 4, sym_1("pixels"));
+  tag_init_array(map->value + 4, sym_1("U8"), 0, NULL);
+  tag_init_sym(    map->key + 5, sym_1("w"));
+  tag_init_uw(   map->value + 5, 0);
+  tag_init_sym(    map->key + 6, sym_1("x"));
+  tag_init_f128( map->value + 6, 0.0);
+  tag_init_sym(    map->key + 7, sym_1("y"));
+  tag_init_f128( map->value + 7, 0.0);
+  tag_init_sym(    map->key + 8, sym_1("z"));
+  tag_init_f128( map->value + 8, 0.01);
+  glGenTextures(1, &g_mandelbrot_f128_texture);
   return true;
 }
 
@@ -41,44 +57,183 @@ bool mandelbrot_f128_render (s_sequence *seq)
 {
   uw *h;
   s_map *map;
+  f128 next_x;
+  f128 next_y;
+  f128 next_z;
   uw *w;
   s_window_sdl2 *win;
   f128 *x;
   f128 *y;
   f128 *z;
   assert(seq);
+  assert(glGetError() == GL_NO_ERROR);
   assert(seq->window);
   win = seq->window;
   assert(seq->tag.type == TAG_MAP);
   map = &seq->tag.data.map;
+  assert(map->count == 9);
   assert(map->key[0].type == TAG_SYM);
   assert(map->key[0].data.sym == sym_1("h"));
   assert(map->value[0].type == TAG_UW);
   h = &map->value[0].data.uw;
   assert(map->key[1].type == TAG_SYM);
-  assert(map->key[1].data.sym == sym_1("w"));
-  assert(map->value[1].type == TAG_UW);
-  w = &map->value[1].data.uw;
+  assert(map->key[1].data.sym == sym_1("next_x"));
+  assert(map->value[1].type == TAG_F128);
+  next_x = map->value[1].data.f128;
   assert(map->key[2].type == TAG_SYM);
-  assert(map->key[2].data.sym == sym_1("x"));
+  assert(map->key[2].data.sym == sym_1("next_y"));
   assert(map->value[2].type == TAG_F128);
-  x = &map->value[2].data.f128;
+  next_y = map->value[2].data.f128;
   assert(map->key[3].type == TAG_SYM);
-  assert(map->key[3].data.sym == sym_1("y"));
+  assert(map->key[3].data.sym == sym_1("next_z"));
   assert(map->value[3].type == TAG_F128);
-  y = &map->value[3].data.f128;
-  assert(map->key[4].type == TAG_SYM);
-  assert(map->key[4].data.sym == sym_1("z"));
-  assert(map->value[4].type == TAG_F128);
-  z = &map->value[4].data.f128;
+  next_z = map->value[3].data.f128;
+  assert(map->key[5].type == TAG_SYM);
+  assert(map->key[5].data.sym == sym_1("w"));
+  assert(map->value[5].type == TAG_UW);
+  w = &map->value[5].data.uw;
+  assert(map->key[6].type == TAG_SYM);
+  assert(map->key[6].data.sym == sym_1("x"));
+  assert(map->value[6].type == TAG_F128);
+  x = &map->value[6].data.f128;
+  assert(map->key[7].type == TAG_SYM);
+  assert(map->key[7].data.sym == sym_1("y"));
+  assert(map->value[7].type == TAG_F128);
+  y = &map->value[7].data.f128;
+  assert(map->key[8].type == TAG_SYM);
+  assert(map->key[8].data.sym == sym_1("z"));
+  assert(map->value[8].type == TAG_F128);
+  z = &map->value[8].data.f128;
   if (*w != win->w || *h != win->h)
-    mandelbrot_f128_resize(seq);
-  assert(glGetError() == GL_NO_ERROR);
+    if (! mandelbrot_f128_resize(seq))
+      return false;
+  if (*w != win->w || *h != win->h ||
+      *x != next_x || *y != next_y || *z != next_z) {
+    mandelbrot_f128_update(seq);
+    *w = win->w;
+    *h = win->h;
+    *x = next_x;
+    *y = next_y;
+    *z = next_z;
+  }
+  gl_matrix_4f_init_identity(&g_ortho.model_matrix);
+  gl_ortho_bind_texture(&g_ortho, g_mandelbrot_f128_texture);
+  gl_ortho_rect(&g_ortho, 0, 0, win->w, win->h);
+  return true;
+}
+
+static bool mandelbrot_f128_resize (s_sequence *seq)
+{
+  uw dim[3];
+  s_map *map;
+  s_array *pixels;
+  s_window_sdl2 *win;
+  assert(seq);
+  win = seq->window;
+  assert(win);
+  assert(seq->tag.type == TAG_MAP);
+  map = &seq->tag.data.map;
+  assert(map->key[4].type == TAG_SYM);
+  assert(map->key[4].data.sym == sym_1("pixels"));
+  assert(map->value[4].type == TAG_ARRAY);
+  pixels = &map->value[4].data.array;
+  array_free(pixels);
+  dim[0] = win->h;
+  dim[1] = win->w;
+  dim[2] = 4;
+  if (! array_init(pixels, &g_sym_U8, 3, dim))
+    return false;
+  if (! array_allocate(pixels))
+    return false;
   return true;
 }
 
 bool mandelbrot_f128_unload (s_sequence *seq)
 {
   (void) seq;
+  glDeleteTextures(1, &g_mandelbrot_f128_texture);
+  return true;
+}
+
+static bool mandelbrot_f128_update (s_sequence *seq)
+{
+  f128 _2z_xz_y;
+  f128 c_x;
+  f128 c_y;
+  uw i;
+  uw j;
+  u8 k;
+  u8 level;
+  s_map *map;
+  f128 next_x;
+  f128 next_y;
+  f128 next_z;
+  u8 *pix;
+  s_array *pixels;
+  s_window_sdl2 *win;
+  f128 z_x;
+  f128 z_y;
+  f128 z_x2;
+  f128 z_y2;
+  assert(seq);
+  assert(seq->window);
+  win = seq->window;
+  assert(seq->tag.type == TAG_MAP);
+  map = &seq->tag.data.map;
+  assert(map->count == 9);
+  assert(map->key[1].type == TAG_SYM);
+  assert(map->key[1].data.sym == sym_1("next_x"));
+  assert(map->value[1].type == TAG_F128);
+  next_x = map->value[1].data.f128;
+  assert(map->key[2].type == TAG_SYM);
+  assert(map->key[2].data.sym == sym_1("next_y"));
+  assert(map->value[2].type == TAG_F128);
+  next_y = map->value[2].data.f128;
+  assert(map->key[3].type == TAG_SYM);
+  assert(map->key[3].data.sym == sym_1("next_z"));
+  assert(map->value[3].type == TAG_F128);
+  next_z = map->value[3].data.f128;
+  assert(map->key[4].type == TAG_SYM);
+  assert(map->key[4].data.sym == sym_1("pixels"));
+  assert(map->value[4].type == TAG_ARRAY);
+  pixels = &map->value[4].data.array;
+  pix = pixels->data;
+  assert(pix);
+  i = 0;
+  while (i < win->h) {
+    c_y = next_y + next_z * (i - win->h / 2);
+    j = 0;
+    while (j < win->w) {
+      c_x = next_x + next_z * (j - win->w / 2);
+      z_x = c_x;
+      z_y = c_y;
+      k = 0;
+      z_x2 = z_x * z_x;
+      z_y2 = z_y * z_y;
+      while (k < 255 && z_x2 + z_y2 < 4) {
+        _2z_xz_y = 2 * z_x * z_y;
+        z_x = c_x + z_x2 - z_y2;
+        z_y = c_y + _2z_xz_y;
+        z_x2 = z_x * z_x;
+        z_y2 = z_y * z_y;
+        k++;
+      }
+      level = (f32) k / 255.0f;
+      pix[0] = level;
+      pix[1] = level;
+      pix[2] = level;
+      pix[3] = 255;
+      pix += 4;
+      j++;
+    }
+    i++;
+  }
+  glBindTexture(GL_TEXTURE_2D, g_mandelbrot_f128_texture);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, win->w, win->h, 0,
+               GL_RGBA, GL_UNSIGNED_BYTE, pixels->data);
   return true;
 }
diff --git a/libc3/window/sdl2/demo/window_sdl2_demo.c b/libc3/window/sdl2/demo/window_sdl2_demo.c
index d149790..45ccbef 100644
--- a/libc3/window/sdl2/demo/window_sdl2_demo.c
+++ b/libc3/window/sdl2/demo/window_sdl2_demo.c
@@ -27,8 +27,9 @@
 #include "toasters.h"
 #include "flies.h"
 #include "earth.h"
+#include "mandelbrot_f128.h"
 
-#define WINDOW_SDL2_DEMO_SEQUENCE_COUNT 5
+#define WINDOW_SDL2_DEMO_SEQUENCE_COUNT 6
 
 //s_gl_font   g_font_computer_modern = {0};
 s_gl_font   g_font_courier_new = {0};
@@ -200,9 +201,10 @@ bool window_sdl2_demo_load (s_window_sdl2 *window)
   assert(glGetError() == GL_NO_ERROR);
   sequence_init(window->sequence + 4, 120.0, "05. Earth",
                 earth_load, earth_render, earth_unload, window);
-  assert(glGetError() == GL_NO_ERROR);
+  sequence_init(window->sequence + 5, 3600.0, "06. Mandelbrot (f128)",
+                mandelbrot_f128_load, mandelbrot_f128_render,
+                mandelbrot_f128_unload, window);
   window_set_sequence_pos((s_window *) window, 0);
-  assert(glGetError() == GL_NO_ERROR);
   return true;
 }