diff --git a/libc3/window/sdl2/demo/lightspeed.c b/libc3/window/sdl2/demo/lightspeed.c
new file mode 100644
index 0000000..0eb76ad
--- /dev/null
+++ b/libc3/window/sdl2/demo/lightspeed.c
@@ -0,0 +1,87 @@
+/* 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 <libc3/c3.h>
+#include "lightspeed.h"
+
+static void star_init (s_tag *star)
+{
+ f64 x;
+ f64 y;
+ f64_random(&x);
+ f64_random(&y);
+ tag_init_map(star, 3);
+ tag_init_sym(star->data.map.keys, sym_1("speed"));
+ tag_init_f64(star->data.map.values, 0.0);
+ tag_init_sym(star->data.map.keys + 1, sym_1("x"));
+ tag_init_f64(star->data.map.values + 1, 2.0 * x - 1.0);
+ tag_init_sym(star->data.map.keys + 2, sym_1("y"));
+ tag_init_f64(star->data.map.values + 2, 2.0 * y - 1.0);
+}
+
+static void star_render (s_tag *star, s_sequence *seq)
+{
+ f64 q;
+ f64 *speed;
+ f64 *x;
+ f64 *y;
+ speed = &star->data.map.values[0].data.f64;
+ x = &star->data.map.values[1].data.f64;
+ y = &star->data.map.values[2].data.f64;
+ glVertex2d(*x, *y);
+ q = (1 + *speed / 20);
+ glVertex2d(*x * q, *y * q);
+ q = (1 + *speed / 100);
+ *x = *x * q;
+ *y = *y * q;
+ *speed += seq->dt;
+ if (*x < -1.0 || *x > 1.0 || *y < -1.0 || *y > 1.0)
+ star_init(star);
+}
+
+bool lightspeed_load (s_sequence *seq, s_window_sdl2 *window)
+{
+ uw i;
+ (void) window;
+ tag_tuple(&seq->tag, LIGHTSPEED_STARS);
+ i = 0;
+ while (i < LIGHTSPEED_STARS) {
+ star_init(seq->tag.data.tuple.tag + i);
+ i++;
+ }
+ return true;
+}
+
+bool lightspeed_render (s_sequence *seq, s_window_sdl2 *window,
+ void *context)
+{
+ uw i;
+ (void) window;
+ (void) context;
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ //glScale2d(window->w / 2.0, window->h / 2.0);
+ //glTranslatef(1.0f, 1.0f, 0.0f);
+ glClearColor(0, 0, 0, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glLineWidth(0.004);
+ glColor3f(1, 1, 1);
+ glBegin(GL_LINES);
+ i = 0;
+ while (i < LIGHTSPEED_STARS) {
+ star_render(seq->tag.data.tuple.tag + i, seq);
+ i++;
+ }
+ return true;
+}
diff --git a/libc3/window/sdl2/demo/lightspeed.h b/libc3/window/sdl2/demo/lightspeed.h
new file mode 100644
index 0000000..bda531a
--- /dev/null
+++ b/libc3/window/sdl2/demo/lightspeed.h
@@ -0,0 +1,24 @@
+/* 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 LIGHTSPEED_H
+#define LIGHTSPEED_H
+
+#include "../types.h"
+
+#define LIGHTSPEED_STARS 2000
+
+bool lightspeed_load (s_sequence *seq, s_window_sdl2 *window);
+bool lightspeed_render (s_sequence *seq, s_window_sdl2 *window,
+ void *context);
+
+#endif /* LIGHTSPEED_H */
diff --git a/libc3/window/sdl2/demo/sources.mk b/libc3/window/sdl2/demo/sources.mk
index 23edeee..37f994f 100644
--- a/libc3/window/sdl2/demo/sources.mk
+++ b/libc3/window/sdl2/demo/sources.mk
@@ -1,8 +1,10 @@
# sources.mk generated by update_sources
HEADERS = \
bg_rect.h \
+ lightspeed.h \
SOURCES = \
bg_rect.c \
+ lightspeed.c \
window_sdl2_demo.c \
diff --git a/libc3/window/sdl2/demo/sources.sh b/libc3/window/sdl2/demo/sources.sh
index 029f297..6e630ef 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 '
-SOURCES='bg_rect.c window_sdl2_demo.c '
+HEADERS='bg_rect.h lightspeed.h '
+SOURCES='bg_rect.c lightspeed.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 4622693..8a10345 100644
--- a/libc3/window/sdl2/demo/window_sdl2_demo.c
+++ b/libc3/window/sdl2/demo/window_sdl2_demo.c
@@ -17,8 +17,9 @@
#include "../window_sdl2.h"
#include "../sdl2_font.h"
#include "bg_rect.h"
+#include "lightspeed.h"
-#define WINDOW_SDL2_DEMO_SEQUENCE_COUNT 1
+#define WINDOW_SDL2_DEMO_SEQUENCE_COUNT 2
//static s_sdl2_font g_font_computer_modern;
static s_sdl2_font g_font_courier_new;
@@ -129,10 +130,10 @@ bool window_sdl2_demo_load (s_window_sdl2 *window)
window_sdl2_sequence_init(window->sequence, 8.0,
"01. Background rectangles",
bg_rect_load, bg_rect_render);
- /*
window_sdl2_sequence_init(window->sequence + 1, 20.0,
"02. Lightspeed",
lightspeed_load, lightspeed_render);
+ /*
if (! sdl2_sprite_init(&g_toaster_sprite,
sdl2_png_1("img/flaps.png"),
4, 1, 4))
@@ -220,7 +221,7 @@ bool window_sdl2_demo_render (s_window_sdl2 *window, void *context)
12 + 2);
/* fps */
s8 fps[32];
- snprintf(fps, sizeof(fps), "%f", (f64) seq->frame / seq->t);
+ snprintf(fps, sizeof(fps), "%.2f", (f64) seq->frame / seq->t);
render_text(&g_font_courier_new, 20, window->h - 30, fps);
return true;
}