diff --git a/libc3/window/sdl2/demo/flies.c b/libc3/window/sdl2/demo/flies.c
new file mode 100644
index 0000000..96c8e59
--- /dev/null
+++ b/libc3/window/sdl2/demo/flies.c
@@ -0,0 +1,310 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#include <math.h>
+#include <libc3/c3.h>
+#include "../window_sdl2.h"
+#include "../sdl2_font.h"
+#include "../sdl2_sprite.h"
+#include "flies.h"
+
+#define BOARD_SIZE 25
+#define FLY_TIME_MAX 200
+
+typedef enum {
+ BOARD_ITEM_SPACE = 0,
+ BOARD_ITEM_BLOCK = 1,
+ BOARD_ITEM_FLY = 2,
+ BOARD_ITEM_DEAD_FLY = 3
+} e_board_item_type;
+
+static const u8 g_board_item_space = BOARD_ITEM_SPACE;
+static const u8 g_board_item_block = BOARD_ITEM_BLOCK;
+static const u8 g_board_item_fly = BOARD_ITEM_FLY;
+static const u8 g_board_item_dead_fly = BOARD_ITEM_DEAD_FLY;
+s_sdl2_sprite g_dead_fly_sprite = {0};
+s_sdl2_sprite g_fly_sprite = {0};
+static const f64 g_xy_ratio = 0.666;
+
+static void fly_init (s_map *map)
+{
+ uw address[2] = { BOARD_SIZE / 2,
+ 0 };
+ s_array *board;
+ uw *in;
+ f64 *t;
+ board = &map->values[0].data.array;
+ in = &map->values[1].data.uw;
+ t = &map->values[3].data.f64;
+ array_data_set(board, address, &g_board_item_fly);
+ *t = 0.0;
+ (*in)++;
+}
+
+bool flies_load (s_sequence *seq,
+ s_window_sdl2 *window)
+{
+ uw address[2];
+ s_array *board;
+ uw i;
+ uw j;
+ s_map *map;
+ (void) window;
+ tag_map(&seq->tag, 4);
+ map = &seq->tag.data.map;
+ tag_init_sym_1( map->keys + 0, "board");
+ tag_init_array(map->values + 0, sym_1("U8"),
+ 2, (uw[]) {BOARD_SIZE, BOARD_SIZE});
+ tag_init_sym_1(map->keys + 1, "in");
+ tag_init_uw( map->values + 1, 0);
+ tag_init_sym_1(map->keys + 2, "out");
+ tag_init_uw( map->values + 2, 0);
+ tag_init_sym_1(map->keys + 3, "t");
+ tag_init_uw( map->values + 3, 0);
+ board = &map->values[0].data.array;
+ board->data = malloc(board->size);
+ i = 0;
+ while (i < BOARD_SIZE) {
+ address[0] = i;
+ j = 0;
+ while (j < BOARD_SIZE) {
+ address[1] = j;
+ array_data_set(board, address, &g_board_item_space);
+ j++;
+ }
+ i++;
+ }
+ i = 0;
+ while (i < BOARD_SIZE) {
+ address[0] = i;
+ address[1] = 0;
+ array_data_set(board, address, &g_board_item_block);
+ address[1] = BOARD_SIZE - 1;
+ array_data_set(board, address, &g_board_item_block);
+ address[0] = 0;
+ address[1] = i;
+ array_data_set(board, address, &g_board_item_block);
+ address[0] = BOARD_SIZE - 1;
+ array_data_set(board, address, &g_board_item_block);
+ i++;
+ }
+ address[0] = BOARD_SIZE / 2;
+ address[1] = 0;
+ array_data_set(board, address, &g_board_item_space);
+ address[1] = BOARD_SIZE - 1;
+ array_data_set(board, address, &g_board_item_space);
+ address[1] = BOARD_SIZE / 2;
+ i = 1;
+ while (i <= BOARD_SIZE / 2) {
+ address[0] = i;
+ array_data_set(board, address, &g_board_item_block);
+ i++;
+ }
+ address[0] = BOARD_SIZE / 2;
+ j = BOARD_SIZE / 4;
+ while (j < BOARD_SIZE / 2) {
+ address[1] = j;
+ array_data_set(board, address, &g_board_item_block);
+ j++;
+ }
+ address[1] = BOARD_SIZE * 3 / 4;
+ i = BOARD_SIZE / 4;
+ while (i < BOARD_SIZE - 1) {
+ address[0] = i;
+ array_data_set(board, address, &g_board_item_block);
+ i++;
+ }
+ fly_init(map);
+ return true;
+}
+
+bool flies_render (s_sequence *seq, s_window_sdl2 *window,
+ void *context)
+{
+ s8 a[BOARD_SIZE];
+ uw address[2];
+ s_array *board;
+ f64 board_w;
+ f64 board_h;
+ f64 board_x;
+ u8 *board_item;
+ f64 board_item_w;
+ f64 board_item_h;
+ s_buf buf;
+ f64 dead_fly_scale;
+ u8 direction;
+ u8 direction_prev = 4;
+ bool directions[9];
+ uw fly_address[2];
+ uw *fly_in;
+ uw fly_prev_address[2];
+ uw *fly_out;
+ f64 fly_scale;
+ uw *fly_time;
+ uw i;
+ uw j;
+ s_map *map;
+ uw r;
+ uw random_bits = 0;
+ f64 x;
+ f64 y;
+ (void) context;
+ glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ /* io_inspect(&seq->tag); */
+ if (seq->tag.type == TAG_MAP) {
+ map = &seq->tag.data.map;
+ if (map->count == 4 &&
+ map->values[0].type == TAG_ARRAY &&
+ map->values[1].type == TAG_UW &&
+ map->values[2].type == TAG_UW &&
+ map->values[3].type == TAG_UW) {
+ board = &map->values[0].data.array;
+ fly_in = &map->values[1].data.uw;
+ fly_out = &map->values[2].data.uw;
+ fly_time = &map->values[3].data.uw;
+ board_item_h = (f64) (window->h - 60) / (BOARD_SIZE + 1);
+ board_item_w = board_item_h * g_xy_ratio;
+ board_w = board_item_w * BOARD_SIZE;
+ board_h = board_item_h * BOARD_SIZE;
+ board_x = (window->w - board_w) / 2.0;
+ fly_scale = 2.0 * board_item_w / g_fly_sprite.w;
+ dead_fly_scale = 2.0 * board_item_w / g_dead_fly_sprite.w;
+ glPushMatrix();
+ glTranslated(board_x, 60.0, 0.0);
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ sdl2_font_set_size(&g_font_courier_new, board_item_h, window->dpi);
+ buf_init(&buf, false, sizeof(a), a);
+ buf_write_1(&buf, "In ");
+ buf_inspect_uw(&buf, fly_in);
+ buf_write_u8(&buf, 0);
+ sdl2_font_render_text(&g_font_courier_new, buf.ptr.ps8);
+ buf_init(&buf, false, sizeof(a), a);
+ buf_write_1(&buf, "Out ");
+ buf_inspect_uw(&buf, fly_out);
+ buf_write_u8(&buf, 0);
+ x = board_item_w * (BOARD_SIZE / 2 + 1);
+ glPushMatrix();
+ glTranslated(x, 0.0, 0.0);
+ sdl2_font_render_text(&g_font_courier_new, buf.ptr.ps8);
+ glPopMatrix();
+ glTranslated(0.0, board_item_h, 0.0);
+ glColor4f(0.6f, 0.7f, 0.9f, 1.0f);
+ glRectd(0, 0, board_w, board_h);
+ address[1] = 0;
+ while (address[1] < BOARD_SIZE) {
+ y = board_item_h * address[1];
+ address[0] = 0;
+ while (address[0] < BOARD_SIZE) {
+ x = board_item_w * address[0];
+ glPushMatrix();
+ glTranslated(x, board_h - board_item_h - y, 0.0);
+ board_item = (u8 *) array_data(board, address);
+ assert(board_item);
+ switch (*board_item) {
+ case BOARD_ITEM_SPACE:
+ break;
+ case BOARD_ITEM_BLOCK:
+ glDisable(GL_TEXTURE_2D);
+ glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
+ glRectd(0, 0, board_item_w + 1.0, board_item_h + 1.0);
+ break;
+ case BOARD_ITEM_FLY:
+ glPushMatrix();
+ glTranslated(-board_item_w / 2.0, -board_item_h / 2.0, 0.0);
+ glScaled(fly_scale, fly_scale, 1.0);
+ sdl2_sprite_render(&g_fly_sprite, 0);
+ glPopMatrix();
+ if (address[0] == BOARD_SIZE / 2 &&
+ address[1] == BOARD_SIZE - 1) {
+ array_data_set(board, address, &g_board_item_space);
+ (*fly_out)++;
+ fly_init(map);
+ break;
+ }
+ fly_address[0] = address[0];
+ fly_address[1] = address[1];
+ i = 0;
+ while (i < 3) {
+ j = 0;
+ while (j < 9) {
+ directions[j] = true;
+ j++;
+ }
+ while (directions[0] | directions[1] | directions[2] |
+ directions[3] | directions[4] | directions[5] |
+ directions[6] | directions[7] | directions[8]) {
+ if (random_bits < 4) {
+ r = random();
+ random_bits = 31;
+ }
+ direction = r % 16;
+ r >>= 4;
+ random_bits -= 4;
+ if (direction >= 12)
+ direction = direction_prev;
+ if (direction >= 9)
+ direction = (direction - 6) % 3 + 6;
+ fly_prev_address[0] = fly_address[0];
+ fly_prev_address[1] = fly_address[1];
+ switch (direction) {
+ case 0: fly_address[0]--; fly_address[1]--; break;
+ case 1: fly_address[1]--; break;
+ case 2: fly_address[0]++; fly_address[1]--; break;
+ case 3: fly_address[0]--; ; break;
+ case 4: ; break;
+ case 5: fly_address[0]++; ; break;
+ case 6: fly_address[0]--; fly_address[1]++; break;
+ case 7: fly_address[1]++; break;
+ case 8: fly_address[0]++; fly_address[1]++; break;
+ }
+ if (fly_address[0] < BOARD_SIZE &&
+ fly_address[1] < BOARD_SIZE &&
+ (board_item = (u8 *) array_data(board,
+ fly_address)) &&
+ *board_item == g_board_item_space) {
+ array_data_set(board, fly_prev_address,
+ &g_board_item_space);
+ array_data_set(board, fly_address, &g_board_item_fly);
+ direction_prev = direction;
+ break;
+ }
+ directions[direction] = false;
+ fly_address[0] = fly_prev_address[0];
+ fly_address[1] = fly_prev_address[1];
+ }
+ i++;
+ }
+ *fly_time += 1;
+ if (*fly_time > FLY_TIME_MAX) {
+ array_data_set(board, fly_address, &g_board_item_dead_fly);
+ fly_init(map);
+ }
+ break;
+ case BOARD_ITEM_DEAD_FLY:
+ glPushMatrix();
+ glTranslated(-board_item_w / 2.0, -board_item_h / 2.0, 0.0);
+ glScaled(dead_fly_scale, dead_fly_scale, 1.0);
+ sdl2_sprite_render(&g_dead_fly_sprite, 0);
+ glPopMatrix();
+ break;
+ }
+ glPopMatrix();
+ address[0]++;
+ }
+ address[1]++;
+ }
+ glPopMatrix();
+ }
+ }
+ return true;
+}
diff --git a/libc3/window/sdl2/demo/flies.h b/libc3/window/sdl2/demo/flies.h
new file mode 100644
index 0000000..0f4fb4b
--- /dev/null
+++ b/libc3/window/sdl2/demo/flies.h
@@ -0,0 +1,26 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#ifndef FLIES_H
+#define FLIES_H
+
+#include "../types.h"
+#include "window_sdl2_demo.h"
+
+extern s_sdl2_sprite g_dead_fly_sprite;
+extern s_sdl2_sprite g_fly_sprite;
+
+bool flies_load (s_sequence *seq, s_window_sdl2 *window);
+bool flies_render (s_sequence *seq, s_window_sdl2 *window,
+ void *context);
+
+#endif /* FLIES_H */
diff --git a/libc3/window/sdl2/demo/sources.mk b/libc3/window/sdl2/demo/sources.mk
index bbb3873..cfa2451 100644
--- a/libc3/window/sdl2/demo/sources.mk
+++ b/libc3/window/sdl2/demo/sources.mk
@@ -1,11 +1,13 @@
# sources.mk generated by update_sources
HEADERS = \
bg_rect.h \
+ flies.h \
lightspeed.h \
toasters.h \
SOURCES = \
bg_rect.c \
+ flies.c \
lightspeed.c \
toasters.c \
window_sdl2_demo.c \
diff --git a/libc3/window/sdl2/demo/sources.sh b/libc3/window/sdl2/demo/sources.sh
index 8301e71..47c2b90 100644
--- a/libc3/window/sdl2/demo/sources.sh
+++ b/libc3/window/sdl2/demo/sources.sh
@@ -1,3 +1,3 @@
# sources.sh generated by update_sources
-HEADERS='bg_rect.h lightspeed.h toasters.h '
-SOURCES='bg_rect.c lightspeed.c toasters.c window_sdl2_demo.c '
+HEADERS='bg_rect.h flies.h lightspeed.h toasters.h '
+SOURCES='bg_rect.c flies.c lightspeed.c toasters.c window_sdl2_demo.c '
diff --git a/libc3/window/sdl2/demo/window_sdl2_demo.c b/libc3/window/sdl2/demo/window_sdl2_demo.c
index 85dd299..4487120 100644
--- a/libc3/window/sdl2/demo/window_sdl2_demo.c
+++ b/libc3/window/sdl2/demo/window_sdl2_demo.c
@@ -20,11 +20,12 @@
#include "bg_rect.h"
#include "lightspeed.h"
#include "toasters.h"
+#include "flies.h"
-#define WINDOW_SDL2_DEMO_SEQUENCE_COUNT 3
+#define WINDOW_SDL2_DEMO_SEQUENCE_COUNT 4
-//static s_sdl2_font g_font_computer_modern;
-static s_sdl2_font g_font_courier_new;
+//s_sdl2_font g_font_computer_modern;
+s_sdl2_font g_font_courier_new = {0};
static bool window_sdl2_demo_button (s_window_sdl2 *window, u8 button,
sw x, sw y);
@@ -144,7 +145,6 @@ bool window_sdl2_demo_load (s_window_sdl2 *window)
window_sdl2_sequence_init(window->sequence + 2, 60.0,
"03. Toasters",
toasters_load, toasters_render);
- /*
if (! sdl2_sprite_init(&g_fly_sprite, "img/fly-noto.png",
1, 1, 1))
return false;
@@ -154,7 +154,6 @@ bool window_sdl2_demo_load (s_window_sdl2 *window)
window_sdl2_sequence_init(window->sequence + 3, 60.0,
"04. Flies",
flies_load, flies_render);
- */
window_set_sequence_pos((s_window *) window, 0);
return true;
}
diff --git a/libc3/window/sdl2/demo/window_sdl2_demo.h b/libc3/window/sdl2/demo/window_sdl2_demo.h
new file mode 100644
index 0000000..57e8e45
--- /dev/null
+++ b/libc3/window/sdl2/demo/window_sdl2_demo.h
@@ -0,0 +1,21 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#ifndef LIBC3_WINDOW_SDL2_DEMO_H
+#define LIBC3_WINDOW_SDL2_DEMO_H
+
+#include "../types.h"
+
+extern s_sdl2_font g_font_computer_modern;
+extern s_sdl2_font g_font_courier_new;
+
+#endif /* LIBC3_WINDOW_SDL2_DEMO_H */