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;
}