diff --git a/.gitignore b/.gitignore
index 56d0187..8415e0d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,44 +45,6 @@ kc3s/kc3s_debug
*.la
lib/kc3/0.1/ekc3.so
lib/kc3/0.1/http.so
-libkc3_window/cairo/quartz/build
-libkc3_window/cairo/quartz/demo/demo.xcodeproj/project.xcworkspace/xcuserdata
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_asan
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_cov
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_debug
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo.app/Contents/MacOS
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo.app/Contents/Frameworks
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo.app/Contents/fonts
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo.app/Contents/img
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo.app/Contents/lib
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_asan.app/Contents/MacOS
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_asan.app/Contents/Frameworks
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_asan.app/Contents/fonts
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_asan.app/Contents/img
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_asan.app/Contents/lib
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_cov.app/Contents/MacOS
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_cov.app/Contents/Frameworks
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_cov.app/Contents/fonts
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_cov.app/Contents/img
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_cov.app/Contents/lib
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_debug.app/Contents/MacOS
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_debug.app/Contents/Frameworks
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_debug.app/Contents/fonts
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_debug.app/Contents/img
-libkc3_window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_debug.app/Contents/lib
-libkc3_window/cairo/xcb/demo/kc3_window_cairo_xcb_demo
-libkc3_window/cairo/xcb/demo/kc3_window_cairo_xcb_demo_asan
-libkc3_window/cairo/xcb/demo/kc3_window_cairo_xcb_demo_cov
-libkc3_window/cairo/xcb/demo/kc3_window_cairo_xcb_demo_debug
-libkc3_window/sdl2/demo/kc3_window_sdl2_demo
-libkc3_window/sdl2/demo/kc3_window_sdl2_demo_asan
-libkc3_window/sdl2/demo/kc3_window_sdl2_demo_cov
-libkc3_window/sdl2/demo/kc3_window_sdl2_demo_debug
-libkc3_window/sdl2/demo/macos/kc3_window_sdl2_demo.app/
-libkc3_window/sdl2/demo/macos/kc3_window_sdl2_demo_asan.app/
-libkc3_window/sdl2/demo/macos/kc3_window_sdl2_demo_cov.app/
-libkc3_window/sdl2/demo/macos/kc3_window_sdl2_demo_debug.app/
.libs/
*.lo
macos/kc3-v*
@@ -121,3 +83,41 @@ test/libkc3_test_debug
*.tmp
ucd2c/ucd2c
win32/kc3*
+window/cairo/quartz/build
+window/cairo/quartz/demo/demo.xcodeproj/project.xcworkspace/xcuserdata
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_asan
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_cov
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_debug
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo.app/Contents/MacOS
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo.app/Contents/Frameworks
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo.app/Contents/fonts
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo.app/Contents/img
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo.app/Contents/lib
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_asan.app/Contents/MacOS
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_asan.app/Contents/Frameworks
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_asan.app/Contents/fonts
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_asan.app/Contents/img
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_asan.app/Contents/lib
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_cov.app/Contents/MacOS
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_cov.app/Contents/Frameworks
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_cov.app/Contents/fonts
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_cov.app/Contents/img
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_cov.app/Contents/lib
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_debug.app/Contents/MacOS
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_debug.app/Contents/Frameworks
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_debug.app/Contents/fonts
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_debug.app/Contents/img
+window/cairo/quartz/demo/kc3_window_cairo_quartz_demo_debug.app/Contents/lib
+window/cairo/xcb/demo/kc3_window_cairo_xcb_demo
+window/cairo/xcb/demo/kc3_window_cairo_xcb_demo_asan
+window/cairo/xcb/demo/kc3_window_cairo_xcb_demo_cov
+window/cairo/xcb/demo/kc3_window_cairo_xcb_demo_debug
+window/sdl2/demo/kc3_window_sdl2_demo
+window/sdl2/demo/kc3_window_sdl2_demo_asan
+window/sdl2/demo/kc3_window_sdl2_demo_cov
+window/sdl2/demo/kc3_window_sdl2_demo_debug
+window/sdl2/demo/macos/kc3_window_sdl2_demo.app/
+window/sdl2/demo/macos/kc3_window_sdl2_demo_asan.app/
+window/sdl2/demo/macos/kc3_window_sdl2_demo_cov.app/
+window/sdl2/demo/macos/kc3_window_sdl2_demo_debug.app/
diff --git a/Makefile b/Makefile
index f91f752..1684914 100644
--- a/Makefile
+++ b/Makefile
@@ -21,7 +21,7 @@ all:
${MAKE} -C http all
${MAKE} -C httpd all
${MAKE} -C test all
- ${MAKE} -C libkc3_window all
+ ${MAKE} -C window all
asan:
${MAKE} gen
@@ -33,7 +33,7 @@ asan:
${MAKE} -C http asan
${MAKE} -C httpd asan
${MAKE} -C test asan
- ${MAKE} -C libkc3_window asan
+ ${MAKE} -C window asan
build:
${MAKE} gen
@@ -46,7 +46,7 @@ build:
${MAKE} -C http build
${MAKE} -C httpd build
${MAKE} -C test build
- ${MAKE} -C libkc3_window build
+ ${MAKE} -C window build
clean:
${MAKE} -C libtommath clean
@@ -58,7 +58,7 @@ clean:
${MAKE} -C http clean
${MAKE} -C httpd clean
${MAKE} -C test clean
- ${MAKE} -C libkc3_window clean
+ ${MAKE} -C window clean
clean_cov:
${MAKE} -C libtommath clean_cov
@@ -69,7 +69,7 @@ clean_cov:
${MAKE} -C http clean_cov
${MAKE} -C httpd clean_cov
${MAKE} -C test clean_cov
- ${MAKE} -C libkc3_window clean_cov
+ ${MAKE} -C window clean_cov
cov:
${MAKE} gen
@@ -81,7 +81,7 @@ cov:
${MAKE} -C http cov
${MAKE} -C httpd cov
${MAKE} -C test cov
- ${MAKE} -C libkc3_window cov
+ ${MAKE} -C window cov
debug:
${MAKE} -C libtommath debug
@@ -93,31 +93,31 @@ debug:
${MAKE} -C http debug
${MAKE} -C httpd debug
${MAKE} -C test debug
- ${MAKE} -C libkc3_window debug
+ ${MAKE} -C window debug
demo: build
- ${MAKE} -C libkc3_window demo
+ ${MAKE} -C window demo
demo_asan: asan
- ${MAKE} -C libkc3_window demo_asan
+ ${MAKE} -C window demo_asan
demo_cov: cov
- ${MAKE} -C libkc3_window demo_cov
+ ${MAKE} -C window demo_cov
demo_debug: debug
- ${MAKE} -C libkc3_window demo_debug
+ ${MAKE} -C window demo_debug
demo_gl: build
- ${MAKE} -C libkc3_window demo_gl
+ ${MAKE} -C window demo_gl
demo_gl_asan: asan
- ${MAKE} -C libkc3_window demo_gl_asan
+ ${MAKE} -C window demo_gl_asan
demo_gl_cov: cov
- ${MAKE} -C libkc3_window demo_gl_cov
+ ${MAKE} -C window demo_gl_cov
demo_gl_debug: debug
- ${MAKE} -C libkc3_window demo_gl_debug
+ ${MAKE} -C window demo_gl_debug
dist: kc3-${KC3_VERSION}.tar.gz
@@ -131,7 +131,7 @@ distclean:
${MAKE} -C http distclean
${MAKE} -C httpd distclean
${MAKE} -C test distclean
- ${MAKE} -C libkc3_window distclean
+ ${MAKE} -C window distclean
gcovr:
${MAKE} -C libkc3 gcovr
@@ -141,7 +141,7 @@ gcovr:
${MAKE} -C http gcovr
${MAKE} -C httpd gcovr
${MAKE} -C test gcovr
- ${MAKE} -C libkc3_window gcovr
+ ${MAKE} -C window gcovr
if [ -d "$$HOME/Downloads/kc3_gcovr" ]; then bin/gcovr-to-downloads; fi
gdb_demo:
@@ -279,7 +279,7 @@ install:
${MAKE} -C ekc3 install
${MAKE} -C http install
${MAKE} -C httpd install
- ${MAKE} -C libkc3_window install
+ ${MAKE} -C window install
kc3-${KC3_VERSION}.tar.gz: kc3.index
rm -rf kc3-${KC3_VERSION}.old
diff --git a/configure b/configure
index e0fb199..29a8b0b 100755
--- a/configure
+++ b/configure
@@ -49,4 +49,4 @@ config_subdirs \
http \
httpd \
test \
- libkc3_window
+ window
diff --git a/http/configure b/http/configure
index a7ca711..cd07a83 100755
--- a/http/configure
+++ b/http/configure
@@ -59,19 +59,22 @@ CPPFLAGS_ASAN="$CPPFLAGS"
CFLAGS_ASAN="$CFLAGS -DDEBUG -O1 -g"
CFLAGS_ASAN="$CFLAGS_ASAN -fsanitize=address -fno-omit-frame-pointer"
LDFLAGS_ASAN="$LDFLAGS"
-LIBS_ASAN="$LIBS"
+LIBS_LOCAL_ASAN="../libkc3/libkc3_asan.la"
+LIBS_ASAN="$LIBS $LIBS_LOCAL_ASAN"
# Coverage config
CPPFLAGS_COV="$CPPFLAGS"
CFLAGS_COV="$CFLAGS -fprofile-arcs -ftest-coverage"
LDFLAGS_COV="$LDFLAGS --coverage"
-LIBS_COV="$LIBS -lgcov"
+LIBS_LOCAL_COV="../libkc3/libkc3_cov.la"
+LIBS_COV="$LIBS $LIBS_LOCAL_COV -lgcov"
# Debug config
CPPFLAGS_DEBUG="$CPPFLAGS"
CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
LDFLAGS_DEBUG="$LDFLAGS"
-LIBS_DEBUG="$LIBS"
+LIBS_LOCAL_DEBUG="../libkc3/libkc3_debug.la"
+LIBS_DEBUG="$LIBS $LIBS_LOCAL_DEBUG"
# Main config
DEFAULT_CFLAGS="-O2 -fPIC"
@@ -79,7 +82,8 @@ if [ "x$ENV_CFLAGS" = "x" ]; then
CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
fi
CFLAGS="$CFLAGS -DNDEBUG"
-LIBS="$LIBS"
+LIBS_LOCAL="../libkc3/libkc3.la"
+LIBS="$LIBS $LIBS_LOCAL"
echo "LIB = $LIB" >> ${CONFIG_MK}
echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
diff --git a/libkc3/compare.c b/libkc3/compare.c
index 01dfa6f..644b314 100644
--- a/libkc3/compare.c
+++ b/libkc3/compare.c
@@ -1258,12 +1258,31 @@ s8 compare_tag_number (const s_tag *a, const s_tag *b)
break;
default: ;
}
- err_puts("tag_number_compare: not a number");
- assert(! "tag_number_compare: not a number");
+ err_puts("compare_tag: not a number");
+ assert(! "compare_tag: not a number");
abort();
return 0;
}
+s8 compare_time (const s_time *a, const s_time *b)
+{
+ if (a == b)
+ return 0;
+ if (! a)
+ return -1;
+ if (! b)
+ return 1;
+ if (a->tv_sec < b->tv_sec)
+ return -1;
+ if (a->tv_sec > b->tv_sec)
+ return 1;
+ if (a->tv_nsec < b->tv_nsec)
+ return -1;
+ if (a->tv_nsec > b->tv_nsec)
+ return 1;
+ return 0;
+}
+
s8 compare_tuple (const s_tuple *a, const s_tuple *b)
{
uw i = 0;
diff --git a/libkc3/compare.h b/libkc3/compare.h
index 9cd38ef..bd41036 100644
--- a/libkc3/compare.h
+++ b/libkc3/compare.h
@@ -59,6 +59,7 @@ s8 compare_struct (const s_struct *a, const s_struct *b);
s8 compare_struct_type (const s_struct_type *a, const s_struct_type *b);
s8 compare_sym (const s_sym *a, const s_sym *b);
s8 compare_tag (const s_tag *a, const s_tag *b);
+s8 compare_time (const s_time *a, const s_time *b);
s8 compare_tuple (const s_tuple *a, const s_tuple *b);
COMPARE_PROTOTYPE(u8);
COMPARE_PROTOTYPE(u16);
diff --git a/libkc3/env.c b/libkc3/env.c
index b24b6bc..29009a5 100644
--- a/libkc3/env.c
+++ b/libkc3/env.c
@@ -2476,8 +2476,8 @@ bool env_module_load (s_env *env, const s_sym *module)
return false;
}
-const s_tag ** env_module_load_time (s_env *env, const s_sym *module,
- const s_tag **dest)
+const s_time ** env_module_load_time (s_env *env, const s_sym *module,
+ const s_time **dest)
{
s_facts_with_cursor cursor;
const s_fact *fact;
@@ -2486,7 +2486,7 @@ const s_tag ** env_module_load_time (s_env *env, const s_sym *module,
s_tag tag_time_var;
tag_init_sym(&tag_module_name, module);
tag_init_sym(&tag_load_time, &g_sym_load_time);
- tag_init_var(&tag_time_var, &g_sym_Tag);
+ tag_init_var(&tag_time_var, &g_sym_Time);
if (! facts_with(&env->facts, &cursor, (t_facts_spec) {
&tag_module_name, &tag_load_time, &tag_time_var, NULL, NULL }))
return NULL;
@@ -2495,17 +2495,25 @@ const s_tag ** env_module_load_time (s_env *env, const s_sym *module,
facts_with_cursor_clean(&cursor);
return NULL;
}
- *dest = fact->object;
+ if (! tag_is_struct(fact->object, &g_sym_Time)) {
+ err_write_1("env_module_load_time: module ");
+ err_inspect_sym(&module);
+ err_puts(" load time is not a %Time{}");
+ assert(! "env_module_load_time: module load time is not a %Time{}");
+ facts_with_cursor_clean(&cursor);
+ return NULL;
+ }
+ *dest = fact->object->data.struct_.data;
facts_with_cursor_clean(&cursor);
return dest;
}
bool env_module_maybe_reload (s_env *env, const s_sym *module)
{
- const s_tag *load_time = {0};
+ const s_time *load_time = NULL;
s_str path;
bool r = false;
- s_tag tag_mtime;
+ s_time mtime;
if (module_path(module, &env->module_path, KC3_EXT, &path)) {
if (file_access(&path, &g_sym_r))
r = true;
@@ -2524,14 +2532,13 @@ bool env_module_maybe_reload (s_env *env, const s_sym *module)
str_clean(&path);
return env_module_load(env, module);
}
- if (! file_mtime(&path, &tag_mtime)) {
+ if (! file_mtime(&path, &mtime)) {
str_clean(&path);
return false;
}
str_clean(&path);
- if (compare_tag(load_time, &tag_mtime) < 0)
+ if (compare_time(load_time, &mtime) < 0)
r = env_module_load(env, module);
- tag_clean(&tag_mtime);
return r;
}
diff --git a/libkc3/env.h b/libkc3/env.h
index c8ff46c..cb7a821 100644
--- a/libkc3/env.h
+++ b/libkc3/env.h
@@ -22,24 +22,24 @@ void env_clean (s_env *env);
s_env * env_init (s_env *env, int *argc, char ***argv);
/* Observers. */
-const s_tag * env_frames_get (const s_env *env, const s_sym *name);
-s_ident * env_ident_resolve_module (s_env *env,
- const s_ident *ident,
- s_ident *dest);
-const s_sym ** env_module (s_env *env, const s_sym **dest);
-bool * env_module_has_ident (s_env *env, const s_sym *module,
- const s_ident *ident, bool *dest);
-bool * env_module_has_symbol (s_env *env, const s_sym *module,
- const s_sym *sym, bool *dest);
-const s_tag ** env_module_load_time (s_env *env, const s_sym *module,
- const s_tag **dest);
-s_list ** env_module_search_modules (s_env *env,
- const s_sym * const *module,
- s_list **dest);
-s_list ** env_search_modules (s_env *env, s_list **dest);
-bool env_sym_search_modules (s_env *env,
- const s_sym *sym,
- const s_sym **dest);
+const s_tag * env_frames_get (const s_env *env, const s_sym *name);
+s_ident * env_ident_resolve_module (s_env *env,
+ const s_ident *ident,
+ s_ident *dest);
+const s_sym ** env_module (s_env *env, const s_sym **dest);
+bool * env_module_has_ident (s_env *env, const s_sym *module,
+ const s_ident *ident, bool *dest);
+bool * env_module_has_symbol (s_env *env, const s_sym *module,
+ const s_sym *sym, bool *dest);
+const s_time ** env_module_load_time (s_env *env, const s_sym *module,
+ const s_time **dest);
+s_list ** env_module_search_modules (s_env *env,
+ const s_sym * const *module,
+ s_list **dest);
+s_list ** env_search_modules (s_env *env, s_list **dest);
+bool env_sym_search_modules (s_env *env,
+ const s_sym *sym,
+ const s_sym **dest);
/* Operators. */
s_tag * env_def (s_env *env, const s_call *call, s_tag *dest);
diff --git a/libkc3/file.c b/libkc3/file.c
index 92b6989..7981372 100644
--- a/libkc3/file.c
+++ b/libkc3/file.c
@@ -175,10 +175,11 @@ s_list ** file_list (const s_str *path, s_list **dest)
return dest;
}
-s_tag * file_mtime (const s_str *path, s_tag *dest)
+s_time * file_mtime (const s_str *path, s_time *dest)
{
s32 e;
struct stat sb;
+ s_time tmp;
assert(path);
assert(dest);
if (stat(path->ptr.pchar, &sb)) {
@@ -190,13 +191,19 @@ s_tag * file_mtime (const s_str *path, s_tag *dest)
return NULL;
}
#if HAVE_STAT_MTIM
- return time_to_tag(&sb.st_mtim, dest);
+# ifdef __APPLE__
+ tmp.tv_sec = sb.st_mtimespec.tv_sec;
+ tmp.tv_nsec = sb.st_mtimespec.tv_nsec;
+# else
+ tmp.tv_sec = sb.st_mtim.tv_sec;
+ tmp.tv_nsec = sb.st_mtim.tv_nsec;
+# endif
#else
- s_timespec tmp = {0};
tmp.tv_sec = sb.st_mtime;
tmp.tv_nsec = 0;
- return time_to_tag(&tmp, dest);
#endif
+ *dest = tmp;
+ return dest;
}
FILE * file_open (const char *path, const char *mode)
@@ -338,12 +345,26 @@ s_file_stat * file_stat (const s_str *path, s_file_stat *dest)
tmp.st_size = sb.st_size;
tmp.st_blksize = sb.st_blksize;
tmp.st_blocks = sb.st_blocks;
- tmp.st_atim.tv_sec = sb.st_atim.tv_sec;
+#if HAVE_STAT_MTIM
+# ifdef __APPLE__
+ tmp.st_atim.tv_sec = sb.st_mtimespec.tv_sec;
+ tmp.st_atim.tv_nsec = sb.st_mtimespec.tv_nsec;
+# else
+ tmp.st_atim.tv_sec = sb.st_atim.tv_sec;
tmp.st_atim.tv_nsec = sb.st_atim.tv_nsec;
- tmp.st_mtim.tv_sec = sb.st_mtim.tv_sec;
+ tmp.st_mtim.tv_sec = sb.st_mtim.tv_sec;
tmp.st_mtim.tv_nsec = sb.st_mtim.tv_nsec;
- tmp.st_ctim.tv_sec = sb.st_ctim.tv_sec;
+ tmp.st_ctim.tv_sec = sb.st_ctim.tv_sec;
tmp.st_ctim.tv_nsec = sb.st_ctim.tv_nsec;
+# endif
+#else
+ tmp.st_atim.tv_sec = sb.st_atime;
+ tmp.st_atim.tv_nsec = 0;
+ tmp.st_mtim.tv_sec = sb.st_mtime;
+ tmp.st_mtim.tv_nsec = 0;
+ tmp.st_ctim.tv_sec = sb.st_ctime;
+ tmp.st_ctim.tv_nsec = 0;
+#endif
*dest = tmp;
return dest;
}
diff --git a/libkc3/file.h b/libkc3/file.h
index ead39c7..5dfd21c 100644
--- a/libkc3/file.h
+++ b/libkc3/file.h
@@ -25,14 +25,14 @@
#include "types.h"
/* Observers */
-bool file_access (const s_str *path, const s_sym *mode);
-sw file_copy (const char *from, const char *to);
-s_str * file_dirname (const s_str *path, s_str *dest);
-s_str * file_ext (const s_str *path, s_str *dest);
-s_tag * file_mtime (const s_str *path, s_tag *dest);
-s_str * file_read (const s_str *path, s_str *dest);
-s_str * file_search (const s_str *suffix, const s_sym *mode,
- s_str *dest);
+bool file_access (const s_str *path, const s_sym *mode);
+sw file_copy (const char *from, const char *to);
+s_str * file_dirname (const s_str *path, s_str *dest);
+s_str * file_ext (const s_str *path, s_str *dest);
+s_time * file_mtime (const s_str *path, s_time *dest);
+s_str * file_read (const s_str *path, s_str *dest);
+s_str * file_search (const s_str *suffix, const s_sym *mode,
+ s_str *dest);
s_file_stat * file_stat (const s_str *path, s_file_stat *dest);
/* Operators. */
diff --git a/libkc3/kc3.c b/libkc3/kc3.c
index 828df48..0f193dc 100644
--- a/libkc3/kc3.c
+++ b/libkc3/kc3.c
@@ -10,10 +10,10 @@
* AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
* THIS SOFTWARE.
*/
-#include "assert.h"
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
+#include "assert.h"
#include "bool.h"
#include "buf.h"
#include "buf_parse.h"
diff --git a/libkc3/module.c b/libkc3/module.c
index b931c92..e23b124 100644
--- a/libkc3/module.c
+++ b/libkc3/module.c
@@ -51,8 +51,8 @@ bool module_load (const s_sym *module)
return env_module_load(&g_kc3_env, module);
}
-const s_tag ** module_load_time (const s_sym *module,
- const s_tag **dest)
+const s_time ** module_load_time (const s_sym *module,
+ const s_time **dest)
{
return env_module_load_time(&g_kc3_env, module, dest);
}
diff --git a/libkc3/module.h b/libkc3/module.h
index 8b43201..15cb229 100644
--- a/libkc3/module.h
+++ b/libkc3/module.h
@@ -28,20 +28,20 @@ bool module_load (const s_sym *module);
bool module_maybe_reload (const s_sym *module);
/* Observers */
-bool * module_has_ident (const s_sym *module,
- const s_ident *ident,
- bool *dest);
-bool * module_has_symbol (const s_sym *module,
- const s_sym *sym,
+bool * module_has_ident (const s_sym *module,
+ const s_ident *ident,
bool *dest);
-bool * module_is_loading (const s_sym *module, bool *dest);
-const s_tag ** module_load_time (const s_sym *module,
- const s_tag **dest);
-s_str * module_path (const s_sym *module, const s_str *prefix,
- const char *ext, s_str *dest);
-sw module_path_size (const s_sym *module,
- const s_str *prefix,
- const char *ext);
-const s_sym * module_to_sym (const s_sym *module);
+bool * module_has_symbol (const s_sym *module,
+ const s_sym *sym,
+ bool *dest);
+bool * module_is_loading (const s_sym *module, bool *dest);
+const s_time ** module_load_time (const s_sym *module,
+ const s_time **dest);
+s_str * module_path (const s_sym *module, const s_str *prefix,
+ const char *ext, s_str *dest);
+sw module_path_size (const s_sym *module,
+ const s_str *prefix,
+ const char *ext);
+const s_sym * module_to_sym (const s_sym *module);
#endif /* LIBKC3_MODULE_H */
diff --git a/libkc3/sym.c b/libkc3/sym.c
index 4ccfa4e..6d1c4ea 100644
--- a/libkc3/sym.c
+++ b/libkc3/sym.c
@@ -66,6 +66,7 @@ const s_sym g_sym_StructType = {{{NULL}, 10, {"StructType"}}};
const s_sym g_sym_Sw = {{{NULL}, 2, {"Sw"}}};
const s_sym g_sym_Sym = {{{NULL}, 3, {"Sym"}}};
const s_sym g_sym_Tag = {{{NULL}, 3, {"Tag"}}};
+const s_sym g_sym_Time = {{{NULL}, 4, {"Time"}}};
const s_sym g_sym_Tuple = {{{NULL}, 5, {"Tuple"}}};
const s_sym g_sym_U8 = {{{NULL}, 2, {"U8"}}};
const s_sym g_sym_U16 = {{{NULL}, 3, {"U16"}}};
@@ -377,6 +378,7 @@ void sym_init_g_sym (void)
sym_register(&g_sym_Sw, NULL);
sym_register(&g_sym_Sym, NULL);
sym_register(&g_sym_Tag, NULL);
+ sym_register(&g_sym_Time, NULL);
sym_register(&g_sym_Tuple, NULL);
sym_register(&g_sym_U8, NULL);
sym_register(&g_sym_U16, NULL);
diff --git a/libkc3/sym.h b/libkc3/sym.h
index a6f8ac8..b3ff915 100644
--- a/libkc3/sym.h
+++ b/libkc3/sym.h
@@ -69,6 +69,7 @@ extern const s_sym g_sym_StructType;
extern const s_sym g_sym_Sw;
extern const s_sym g_sym_Sym;
extern const s_sym g_sym_Tag;
+extern const s_sym g_sym_Time;
extern const s_sym g_sym_Tuple;
extern const s_sym g_sym_U8;
extern const s_sym g_sym_U16;
diff --git a/libkc3/tag.c b/libkc3/tag.c
index 9431f7c..54dc17d 100644
--- a/libkc3/tag.c
+++ b/libkc3/tag.c
@@ -746,6 +746,13 @@ bool tag_is_number (const s_tag *tag)
return false;
}
+bool tag_is_struct (const s_tag *tag, const s_sym *module)
+{
+ return tag &&
+ tag->type == TAG_STRUCT &&
+ tag->data.struct_.type->module == module;
+}
+
bool * tag_is_unbound_var (const s_tag *tag, bool *dest)
{
assert(tag);
diff --git a/libkc3/tag.h b/libkc3/tag.h
index 6754ad7..13abd07 100644
--- a/libkc3/tag.h
+++ b/libkc3/tag.h
@@ -49,6 +49,7 @@ bool tag_is_alist (const s_tag *tag);
bool tag_is_bound_var (const s_tag *tag);
bool tag_is_cast (const s_tag *tag, const s_sym *type);
bool tag_is_number (const s_tag *tag);
+bool tag_is_struct (const s_tag *tag, const s_sym *module);
bool * tag_is_unbound_var (const s_tag *tag, bool *dest);
bool tag_is_zero(const s_tag *tag);
s8 tag_number_compare (const s_tag *a, const s_tag *b);
diff --git a/libkc3/types.h b/libkc3/types.h
index 0e6dce2..fac1cef 100644
--- a/libkc3/types.h
+++ b/libkc3/types.h
@@ -34,10 +34,6 @@
# undef true
#endif
-#ifdef __APPLE__
-# define st_mtim st_mtimespec
-#endif
-
/* Basic integer types. */
typedef int8_t s8;
typedef int16_t s16;
diff --git a/libkc3_window/Makefile b/libkc3_window/Makefile
deleted file mode 100644
index c7fac7c..0000000
--- a/libkc3_window/Makefile
+++ /dev/null
@@ -1,132 +0,0 @@
-## kc3
-## Copyright 2022-2024 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.
-
-all:
- ${MAKE} build
- ${MAKE} debug
- if ${HAVE_ASAN}; then ${MAKE} asan; fi
- if ${HAVE_GCOV}; then ${MAKE} cov; fi
-
-asan:
- ${MAKE} ${LIB_ASAN}
- if ${HAVE_CAIRO}; then ${MAKE} -C cairo asan; fi
- if ${HAVE_SDL2}; then ${MAKE} -C sdl2 asan; fi
-
-build:
- ${MAKE} ${LIB}
- if ${HAVE_CAIRO}; then ${MAKE} -C cairo build; fi
- if ${HAVE_SDL2}; then ${MAKE} -C sdl2 build; fi
-
-clean:
- if ${HAVE_CAIRO}; then ${MAKE} -C cairo clean; fi
- if ${HAVE_SDL2}; then ${MAKE} -C sdl2 clean; fi
-
-clean_cov:
- if ${HAVE_CAIRO}; then ${MAKE} -C cairo clean_cov; fi
- if ${HAVE_SDL2}; then ${MAKE} -C sdl2 clean_cov; fi
-
-cov:
- ${MAKE} ${LIB_COV}
- if ${HAVE_CAIRO}; then ${MAKE} -C cairo cov; fi
- if ${HAVE_SDL2}; then ${MAKE} -C sdl2 cov; fi
-
-debug:
- ${MAKE} ${LIB_DEBUG}
- if ${HAVE_CAIRO}; then ${MAKE} -C cairo debug; fi
- if ${HAVE_SDL2}; then ${MAKE} -C sdl2 debug; fi
-
-demo: build
- if ${HAVE_CAIRO}; then ${MAKE} -C cairo demo; fi
-
-demo_asan: asan
- if ${HAVE_CAIRO}; then ${MAKE} -C cairo demo_asan; fi
-
-demo_cov: cov
- if ${HAVE_CAIRO}; then ${MAKE} -C cairo demo_cov; fi
-
-demo_debug: debug
- if ${HAVE_CAIRO}; then ${MAKE} -C cairo demo_debug; fi
-
-demo_gl: build
- if ${HAVE_SDL2}; then ${MAKE} -C sdl2 demo; fi
-
-demo_gl_asan: asan
- if ${HAVE_SDL2}; then ${MAKE} -C sdl2 demo_asan; fi
-
-demo_gl_cov: cov
- if ${HAVE_SDL2}; then ${MAKE} -C sdl2 demo_cov; fi
-
-demo_gl_debug: debug
- if ${HAVE_SDL2}; then ${MAKE} -C sdl2 demo_debug; fi
-
-distclean:
- if ${HAVE_CAIRO}; then ${MAKE} -C cairo distclean; fi
- if ${HAVE_SDL2}; then ${MAKE} -C sdl2 distclean; fi
-
-gcovr:
- if ${HAVE_CAIRO}; then ${MAKE} -C cairo gcovr; fi
- if ${HAVE_SDL2}; then ${MAKE} -C sdl2 gcovr; fi
-
-gdb_demo: debug
- if ${HAVE_CAIRO}; then ${MAKE} -C cairo gdb_demo; fi
-
-gdb_demo_gl: debug
- if ${HAVE_SDL2}; then ${MAKE} -C sdl2 gdb_demo; fi
-
-install:
- ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0755 -d ${prefix}/include/libkc3/window
- ${LIBTOOL} --tag=CC --mode=install ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0644 ${HEADERS} ${prefix}/include/libkc3/window
- ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0755 -d ${prefix}/lib
- ${LIBTOOL} --tag=CC --mode=install ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0644 ${LIB} ${prefix}/lib
- ${LIBTOOL} --finish ${prefix}/lib
- if ${HAVE_CAIRO}; then ${MAKE} -C cairo install; fi
- if ${HAVE_SDL2}; then ${MAKE} -C sdl2 install; fi
-
-lldb_demo: debug
- if ${HAVE_CAIRO}; then ${MAKE} -C cairo lldb_demo; fi
-
-lldb_demo_gl: debug
- if ${HAVE_SDL2}; then ${MAKE} -C sdl2 lldb_demo; fi
-
-test:
- if ${HAVE_CAIRO}; then ${MAKE} -C cairo test; fi
- if ${HAVE_SDL2}; then ${MAKE} -C sdl2 test; fi
-
-update_sources:
- ./update_sources
-
-.PHONY: \
- all \
- asan \
- build \
- clean \
- cov \
- debug \
- demo \
- demo_asan \
- demo_cov \
- demo_debug \
- demo_gl \
- demo_gl_asan \
- demo_gl_cov \
- demo_gl_debug \
- distclean \
- gdb_demo \
- gdb_demo_gl \
- install \
- lldb_demo \
- lldb_demo_gl \
- test \
- update_sources
-
-include config.mk
-include sources.mk
diff --git a/libkc3_window/cairo/Makefile b/libkc3_window/cairo/Makefile
deleted file mode 100644
index c4de923..0000000
--- a/libkc3_window/cairo/Makefile
+++ /dev/null
@@ -1,126 +0,0 @@
-## kc3
-## Copyright 2022-2024 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.
-
-build:
- ${MAKE} ${LIB}
- ${MAKE} -C demo build
- if ${HAVE_COCOA}; then ${MAKE} -C quartz build; fi
- if ${HAVE_WIN32}; then ${MAKE} -C win32 build; fi
- if ${HAVE_XCB}; then ${MAKE} -C xcb build; fi
-
-all:
- ${MAKE} build
- if ${HAVE_GCOV}; then ${MAKE} cov; fi
- ${MAKE} debug
- if ${HAVE_ASAN}; then ${MAKE} asan; fi
-
-asan:
- ${MAKE} ${LIB_ASAN}
- ${MAKE} -C demo asan
- if ${HAVE_COCOA}; then ${MAKE} -C quartz asan; fi
- if ${HAVE_WIN32}; then ${MAKE} -C win32 asan; fi
- if ${HAVE_XCB}; then ${MAKE} -C xcb asan; fi
-
-clean:
- ${MAKE} -C demo clean
- if ${HAVE_COCOA}; then ${MAKE} -C quartz clean; fi
- if ${HAVE_WIN32}; then ${MAKE} -C win32 clean; fi
- if ${HAVE_XCB}; then ${MAKE} -C xcb clean; fi
-
-clean_cov:
- ${MAKE} -C demo clean_cov
- if ${HAVE_COCOA}; then ${MAKE} -C quartz clean_cov; fi
- if ${HAVE_WIN32}; then ${MAKE} -C win32 clean_cov; fi
- if ${HAVE_XCB}; then ${MAKE} -C xcb clean_cov; fi
-
-cov:
- ${MAKE} ${LIB_COV}
- ${MAKE} -C demo cov
- if ${HAVE_COCOA}; then ${MAKE} -C quartz cov; fi
- if ${HAVE_WIN32}; then ${MAKE} -C win32 cov; fi
- if ${HAVE_XCB}; then ${MAKE} -C xcb cov; fi
-
-debug:
- ${MAKE} ${LIB_DEBUG}
- ${MAKE} -C demo debug
- if ${HAVE_COCOA}; then ${MAKE} -C quartz debug; else if ${HAVE_WIN32}; then ${MAKE} -C win32 debug; else if ${HAVE_XCB}; then ${MAKE} -C xcb debug; fi; fi; fi
-
-demo: build
- if ${HAVE_COCOA}; then ${MAKE} -C quartz demo; else if ${HAVE_WIN32}; then ${MAKE} -C win32 demo; else if ${HAVE_XCB}; then ${MAKE} -C xcb demo; fi; fi; fi
-
-demo_asan: asan
- if ${HAVE_COCOA}; then ${MAKE} -C quartz demo_asan; else if ${HAVE_WIN32}; then ${MAKE} -C win32 demo_asan; else if ${HAVE_XCB}; then ${MAKE} -C xcb demo_asan; fi; fi; fi
-
-demo_cov: cov
- if ${HAVE_COCOA}; then ${MAKE} -C quartz demo_cov; else if ${HAVE_WIN32}; then ${MAKE} -C win32 demo_cov; else if ${HAVE_XCB}; then ${MAKE} -C xcb demo_cov; fi; fi; fi
-
-demo_debug: debug
- if ${HAVE_COCOA}; then ${MAKE} -C quartz demo_debug; else if ${HAVE_WIN32}; then ${MAKE} -C win32 demo_debug; else if ${HAVE_XCB}; then ${MAKE} -C xcb demo_debug; fi; fi; fi
-
-distclean:
- rm -rf ${DISTCLEANFILES}
- ${MAKE} -C demo distclean
- if ${HAVE_COCOA}; then ${MAKE} -C quartz distclean; fi
- if ${HAVE_WIN32}; then ${MAKE} -C win32 distclean; fi
- if ${HAVE_XCB}; then ${MAKE} -C xcb distclean; fi
-
-gcovr:
- ${MAKE} -C demo gcovr
- if ${HAVE_COCOA}; then ${MAKE} -C quartz gcovr; fi
- if ${HAVE_WIN32}; then ${MAKE} -C win32 gcovr; fi
- if ${HAVE_XCB}; then ${MAKE} -C xcb gcovr; fi
-
-gdb_demo: debug
- if ${HAVE_COCOA}; then ${MAKE} -C quartz gdb_demo; else if ${HAVE_WIN32}; then ${MAKE} -C win32 gdb_demo; else if ${HAVE_XCB}; then ${MAKE} -C xcb gdb_demo; fi; fi; fi
-
-install:
- ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0755 -d ${prefix}/include/libc3/window/cairo
- ${LIBTOOL} --tag=CC --mode=install ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0644 ${HEADERS} ${prefix}/include/libc3/window/cairo
- ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0755 -d ${prefix}/lib
- ${LIBTOOL} --tag=CC --mode=install ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0644 ${LIB} ${prefix}/lib
- ${LIBTOOL} --finish ${prefix}/lib
- if ${HAVE_COCOA}; then ${MAKE} -C quartz install; fi
- if ${HAVE_WIN32}; then ${MAKE} -C win32 install; fi
- if ${HAVE_XCB}; then ${MAKE} -C xcb install; fi
-
-lldb_demo: debug
- if ${HAVE_COCOA}; then ${MAKE} -C quartz lldb_demo; else if ${HAVE_WIN32}; then ${MAKE} -C win32 lldb_demo; else if ${HAVE_XCB}; then ${MAKE} -C xcb lldb_demo; fi; fi; fi
-
-test:
- ${MAKE} -C demo test
- if ${HAVE_COCOA}; then ${MAKE} -C quartz test; fi
- if ${HAVE_WIN32}; then ${MAKE} -C win32 test; fi
- if ${HAVE_XCB}; then ${MAKE} -C xcb test; fi
-
-update_sources:
- ./update_sources
-
-.PHONY: \
- all \
- asan \
- build \
- clean \
- cov \
- debug \
- demo \
- demo_asan \
- demo_cov \
- demo_debug \
- distclean \
- gdb_demo \
- install \
- lldb_demo \
- test \
- update_sources
-
-include config.mk
-include sources.mk
diff --git a/libkc3_window/cairo/cairo_font.c b/libkc3_window/cairo/cairo_font.c
deleted file mode 100644
index e527f38..0000000
--- a/libkc3_window/cairo/cairo_font.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "cairo_font.h"
-
-static FT_Library *g_cairo_font_ft = NULL;
-
-static FT_Library * cairo_font_ft (void);
-
-void c3_window_cairo_font_clean (void)
-{
- if (g_cairo_font_ft) {
- FT_Done_FreeType(*g_cairo_font_ft);
- free(g_cairo_font_ft);
- }
-}
-
-void cairo_font_clean (s_cairo_font *font)
-{
- assert(font);
- cairo_font_face_destroy(font->cairo_font_face);
- FT_Done_Face(font->ft_face);
- str_clean(&font->path);
- str_clean(&font->real_path);
-}
-
-static FT_Library * cairo_font_ft (void)
-{
- if (! g_cairo_font_ft) {
- g_cairo_font_ft = malloc(sizeof(FT_Library));
- if (! g_cairo_font_ft) {
- err_puts("cairo_font_ft: failed to allocate memory");
- return NULL;
- }
- if (FT_Init_FreeType(g_cairo_font_ft)) {
- err_puts("cairo_font_ft: error initializing FreeType");
- free(g_cairo_font_ft);
- g_cairo_font_ft = NULL;
- return NULL;
- }
- }
- return g_cairo_font_ft;
-}
-
-s_cairo_font * cairo_font_init (s_cairo_font *font, const char *path)
-{
- FT_Library *ft;
- assert(font);
- assert(path);
- if (! (ft = cairo_font_ft()))
- return NULL;
- str_init_copy_1(&font->path, path);
- if (! file_search(&font->path, sym_1("r"), &font->real_path)) {
- err_write_1("cairo_font_init: file not found: ");
- err_puts(path);
- str_clean(&font->path);
- return NULL;
- }
- if (FT_New_Face(*ft, font->real_path.ptr.pchar, 0, &font->ft_face)) {
- err_write_1("cairo_font_init: error loading font: ");
- err_puts(font->real_path.ptr.pchar);
- str_clean(&font->path);
- str_clean(&font->real_path);
- return NULL;
- }
- font->cairo_font_face = cairo_ft_font_face_create_for_ft_face
- (font->ft_face, 0);
- return font;
-}
-
-void cairo_set_font (cairo_t *cr, const s_cairo_font *font)
-{
- cairo_set_font_face(cr, font->cairo_font_face);
-}
diff --git a/libkc3_window/cairo/cairo_font.h b/libkc3_window/cairo/cairo_font.h
deleted file mode 100644
index 68c7525..0000000
--- a/libkc3_window/cairo/cairo_font.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_CAIRO_FONT_H
-#define LIBKC3_WINDOW_CAIRO_CAIRO_FONT_H
-
-#include "types.h"
-
-/* Stack-allocation compatible functions, call cairo_font_clean
- after use. */
-void cairo_font_clean (s_cairo_font *font);
-s_cairo_font * cairo_font_init (s_cairo_font *font, const char *path);
-
-/* Observers */
-void cairo_set_font (cairo_t *cr, const s_cairo_font *font);
-
-#endif /* LIBKC3_WINDOW_CAIRO_CAIRO_FONT_H */
diff --git a/libkc3_window/cairo/cairo_sprite.c b/libkc3_window/cairo/cairo_sprite.c
deleted file mode 100644
index 477f6e8..0000000
--- a/libkc3_window/cairo/cairo_sprite.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "cairo_sprite.h"
-
-void cairo_sprite_blit (const s_cairo_sprite *sprite, uw frame,
- cairo_t *cr, uw x, uw y)
-{
- assert(sprite);
- assert(frame < sprite->frame_count);
- assert(cr);
- frame %= sprite->frame_count;
- cairo_set_source_surface(cr, sprite->surface[frame], 0, 0);
- cairo_rectangle(cr, x, y, sprite->w, sprite->h);
- cairo_fill(cr);
-}
-
-void cairo_sprite_clean (s_cairo_sprite *sprite)
-{
- void *data;
- uw i;
- assert(sprite);
- i = 0;
- while (i < sprite->frame_count) {
- data = cairo_image_surface_get_data(sprite->surface[i]);
- cairo_surface_destroy(sprite->surface[i]);
- free(data);
- i++;
- }
- free(sprite->surface);
-}
-
-s_cairo_sprite * cairo_sprite_init (s_cairo_sprite *sprite,
- const char *path,
- uw dim_x, uw dim_y,
- uw frame_count)
-{
- assert(sprite);
- assert(dim_x);
- assert(dim_y);
- u8 *dest_data;
- uw dest_stride;
- uw i;
- cairo_surface_t *src;
- u8 *src_data;
- uw src_stride;
- uw u;
- uw v;
- uw x;
- uw y;
- assert(sprite);
- assert(path);
- assert(dim_x);
- assert(dim_y);
- str_init_copy_1(&sprite->path, path);
- if (! file_search(&sprite->path, sym_1("r"), &sprite->real_path)) {
- err_write_1("cairo_sprite_init: file not found: ");
- err_puts(path);
- str_clean(&sprite->path);
- return NULL;
- }
- src =
- cairo_image_surface_create_from_png(sprite->real_path.ptr.pchar);
- if (! src) {
- err_write_1("cairo_sprite_init: error loading image: ");
- err_puts(sprite->real_path.ptr.pchar);
- str_clean(&sprite->path);
- str_clean(&sprite->real_path);
- return NULL;
- }
- sprite->total_w = cairo_image_surface_get_width(src);
- sprite->total_h = cairo_image_surface_get_height(src);
- sprite->dim_x = dim_x;
- sprite->dim_y = dim_y;
- sprite->w = sprite->total_w / dim_x;
- sprite->h = sprite->total_h / dim_y;
- sprite->frame_count = frame_count ? frame_count : (dim_x * dim_y);
- sprite->surface = calloc(frame_count, sizeof(cairo_surface_t *));
- if (! sprite->surface) {
- err_puts("cairo_sprite_init: sprite->surface:"
- " failed to allocate memory");
- cairo_surface_destroy(src);
- str_clean(&sprite->path);
- str_clean(&sprite->real_path);
- return NULL;
- }
- i = 0;
- y = 0;
- while (i < sprite->frame_count && y < dim_y) {
- x = 0;
- while (i < sprite->frame_count && x < dim_x) {
- src_data = cairo_image_surface_get_data(src);
- src_stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32,
- sprite->total_w);
- dest_stride =
- cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, sprite->w);
- dest_data = malloc(sprite->h * dest_stride);
- sprite->surface[i] =
- cairo_image_surface_create_for_data(dest_data,
- CAIRO_FORMAT_ARGB32,
- sprite->w, sprite->h,
- dest_stride);
- v = 0;
- while (v < sprite->h) {
- u = 0;
- while (u < sprite->w) {
- u8 *dest_pixel = dest_data + v * dest_stride +
- u * 4;
- u8 *src_pixel = src_data +
- (y * sprite->h + v) * src_stride +
- (x * sprite->w + u) * 4;
- dest_pixel[0] = src_pixel[0];
- dest_pixel[1] = src_pixel[1];
- dest_pixel[2] = src_pixel[2];
- dest_pixel[3] = src_pixel[3];
- u++;
- }
- v++;
- }
- i++;
- x++;
- }
- y++;
- }
- cairo_surface_destroy(src);
- return sprite;
-}
diff --git a/libkc3_window/cairo/cairo_sprite.h b/libkc3_window/cairo/cairo_sprite.h
deleted file mode 100644
index 86c2334..0000000
--- a/libkc3_window/cairo/cairo_sprite.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 CAIRO_SPRITE_H
-#define CAIRO_SPRITE_H
-
-#include "types.h"
-#include <cairo.h>
-
-/* stack allocation compatible functions */
-void cairo_sprite_clean (s_cairo_sprite *sprite);
-s_cairo_sprite * cairo_sprite_init (s_cairo_sprite *sprite,
- const char *path,
- uw dim_x, uw dim_y,
- uw frame_count);
-
-/* operations */
-void cairo_sprite_blit (const s_cairo_sprite *sprite, uw frame,
- cairo_t *cr, uw x, uw y);
-
-#endif /* CAIRO_SPRITE_H */
diff --git a/libkc3_window/cairo/cairo_text.c b/libkc3_window/cairo/cairo_text.c
deleted file mode 100644
index d143bb8..0000000
--- a/libkc3_window/cairo/cairo_text.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "cairo_text.h"
-
-void cairo_text_outline (cairo_t *cr, double x, double y,
- const char *p)
-{
- cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
- cairo_move_to(cr, x - 1.0, y - 1.0);
- cairo_show_text(cr, p);
- cairo_move_to(cr, x - 1.0, y);
- cairo_show_text(cr, p);
- cairo_move_to(cr, x - 1.0, y + 1.0);
- cairo_show_text(cr, p);
- cairo_move_to(cr, x, y - 1.0);
- cairo_show_text(cr, p);
- cairo_move_to(cr, x, y + 1.0);
- cairo_show_text(cr, p);
- cairo_move_to(cr, x + 1.0, y - 1.0);
- cairo_show_text(cr, p);
- cairo_move_to(cr, x + 1.0, y);
- cairo_show_text(cr, p);
- cairo_move_to(cr, x + 1.0, y + 1.0);
- cairo_show_text(cr, p);
- cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
- cairo_move_to(cr, x, y);
- cairo_show_text(cr, p);
-}
diff --git a/libkc3_window/cairo/cairo_text.h b/libkc3_window/cairo/cairo_text.h
deleted file mode 100644
index 21533c5..0000000
--- a/libkc3_window/cairo/cairo_text.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_CAIRO_TEXT_H
-#define LIBKC3_WINDOW_CAIRO_CAIRO_TEXT_H
-
-#include "types.h"
-
-/* Stack-allocation compatible functions, call cairo_font_clean
- after use. */
-void cairo_font_clean (s_cairo_font *font);
-s_cairo_font * cairo_font_init (s_cairo_font *font, const char *path);
-
-/* Observers */
-void cairo_text_outline (cairo_t *cr, double x, double y,
- const char *p);
-
-#endif /* LIBKC3_WINDOW_CAIRO_CAIRO_TEXT_H */
diff --git a/libkc3_window/cairo/configure b/libkc3_window/cairo/configure
deleted file mode 100755
index eeaf2da..0000000
--- a/libkc3_window/cairo/configure
+++ /dev/null
@@ -1,151 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-set -e
-
-echo "$PWD/configure"
-
-export SRC_TOP="$(dirname "$PWD")"
-
-CONFIG_H_PREFIX=LIBKC3_WINDOW_CAIRO_
-
-. ../../config.subr
-
-LIB=libkc3_window_cairo.la
-LIB_ASAN=libkc3_window_cairo_asan.la
-LIB_COV=libkc3_window_cairo_cov.la
-LIB_DEBUG=libkc3_window_cairo_debug.la
-
-echo "LIB = $LIB" >> ${CONFIG_MK}
-echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
-echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
-echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
-
-. ./sources.sh
-
-OBJECTS="$(c2ext .main.lo "$SOURCES")"
-echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
-OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
-OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
-OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
-
-# Common config for all targets
-CPPFLAGS="-I../.. $CPPFLAGS"
-OBJCFLAGS="$CFLAGS -W -Wall -Werror"
-CFLAGS="$CFLAGS -W -Wall -Werror -std=c11 -pedantic -pipe"
-LDFLAGS="--shared ${LDFLAGS}"
-LIBS="$LIBS -rpath ${PREFIX}/lib"
-config_asan
-config_gnu
-config_i386
-pkg_config libbsd-overlay
-pkg_config libffi
-pkg_config libmd
-pkg_config cairo
-pkg_config cairo-ft
-pkg_config freetype2
-pkg_config xkbcommon
-config_lib_have COCOA -framework Cocoa
-if $HAVE_COCOA; then
- config_objc_include_have COCOA '#import <Cocoa/Cocoa.h>'
-fi
-config_define PREFIX "\"${PREFIX}\""
-
-# Address Sanitizer config
-CPPFLAGS_ASAN="$CPPFLAGS"
-CFLAGS_ASAN="$CFLAGS -O1 -fsanitize=address -fno-omit-frame-pointer -g"
-LDFLAGS_ASAN="$LDFLAGS"
-LIBS_LOCAL_ASAN="../libkc3_window_asan.la"
-LIBS_ASAN="$LIBS_LOCAL_ASAN $LIBS"
-
-# Coverage config
-CPPFLAGS_COV="$CPPFLAGS"
-CFLAGS_COV="$CFLAGS -ftest-coverage -fprofile-arcs -fprofile-generate"
-LDFLAGS_COV="$LDFLAGS --coverage"
-LIBS_LOCAL_COV="../libkc3_window_cov.la"
-LIBS_COV="$LIBS_LOCAL_COV $LIBS"
-
-# Debug config
-CPPFLAGS_DEBUG="$CPPFLAGS"
-CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
-LDFLAGS_DEBUG="$LDFLAGS"
-LIBS_LOCAL_DEBUG="../libkc3_window_debug.la"
-LIBS_DEBUG="$LIBS_LOCAL_DEBUG $LIBS"
-
-# Main config
-DEFAULT_CFLAGS="-O2 -fPIC"
-if [ "x$ENV_CFLAGS" = "x" ]; then
- CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
-fi
-CFLAGS="$CFLAGS -DNDEBUG"
-LIBS_LOCAL="../libkc3_window.la"
-LIBS="$LIBS_LOCAL $LIBS"
-
-echo "LIB = $LIB" >> ${CONFIG_MK}
-echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
-echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
-echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
-echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
-echo "LIBS = $LIBS" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
-echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
-echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
-echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
-echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
-echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
-
-update_build
-update_build_lib
-
-build_lo
-build_lib
-
-if pkg-config cairo-xcb; then
- HAVE_XCB=true
-else
- HAVE_XCB=false
-fi
-echo "HAVE_XCB = $HAVE_XCB" >> ${CONFIG_MK}
-
-if pkg-config cairo-win32; then
- HAVE_WIN32=true
-else
- HAVE_WIN32=false
-fi
-echo "HAVE_WIN32 = $HAVE_WIN32" >> ${CONFIG_MK}
-
-update_config_mk
-env_reset
-
-config_subdirs demo
-
-if ${HAVE_COCOA}; then
- config_subdirs quartz
-fi
-
-if ${HAVE_WIN32}; then
- config_subdirs win32
-fi
-
-if ${HAVE_XCB}; then
- config_subdirs xcb
-fi
diff --git a/libkc3_window/cairo/demo/Makefile b/libkc3_window/cairo/demo/Makefile
deleted file mode 100644
index bf4c7f2..0000000
--- a/libkc3_window/cairo/demo/Makefile
+++ /dev/null
@@ -1,65 +0,0 @@
-## kc3
-## Copyright 2022-2024 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.
-
-CLEANFILES = *.a *.gcno *.la .libs *.lo *.o
-
-CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
-
-CLEANFILES += ${CLEANFILES_COV}
-
-DISTCLEANFILES = ${CLEANFILES} config.h config.mk
-
-build:
- ${MAKE} ${LIB}
-
-all:
- ${MAKE} build
- if ${HAVE_GCOV}; then ${MAKE} cov; fi
- ${MAKE} debug
- if ${HAVE_ASAN}; then ${MAKE} asan; fi
-
-asan:
- ${MAKE} ${LIB_ASAN}
-
-clean:
- rm -rf ${CLEANFILES}
-
-clean_cov:
- rm -rf ${CLEANFILES_COV}
-
-cov:
- ${MAKE} ${LIB_COV}
-
-debug:
- ${MAKE} ${LIB_DEBUG}
-
-distclean:
- rm -rf ${DISTCLEANFILES}
-
-gcovr:
- gcovr --gcov-executable ${GCOV} --html-details demo.html
-
-update_sources:
- ./update_sources
-
-.PHONY: \
- all \
- asan \
- build \
- clean \
- cov \
- debug \
- distclean \
- update_sources
-
-include config.mk
-include sources.mk
diff --git a/libkc3_window/cairo/demo/bg_rect.c b/libkc3_window/cairo/demo/bg_rect.c
deleted file mode 100644
index f32035a..0000000
--- a/libkc3_window/cairo/demo/bg_rect.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "../types.h"
-#include "bg_rect.h"
-
-#define BG_RECT_COLOR_MAX 8
-
-bool bg_rect_load (s_sequence *seq)
-{
- (void) seq;
- return true;
-}
-
-bool bg_rect_render (s_sequence *seq)
-{
- const s_rgb color[BG_RECT_COLOR_MAX] = {
- {0, 0, 0},
- {1, 0, 0},
- {1, 1, 0},
- {0, 1, 0},
- {0, 1, 1},
- {0, 0, 1},
- {1, 0, 1},
- {1, 1, 1}
- };
- u8 c1;
- u8 c2;
- cairo_t *cr;
- double p;
- double q;
- s_rgb rgb;
- s_window_cairo *window;
- window = seq->window;
- cr = window->cr;
- c1 = (u8) trunc(seq->t) % BG_RECT_COLOR_MAX;
- c2 = (u8) trunc(seq->t + 1.0) % BG_RECT_COLOR_MAX;
- p = fmod(seq->t, 1.0);
- q = 1.0 - p;
- rgb.r = color[c1].r * q + color[c2].r * p;
- rgb.g = color[c1].g * q + color[c2].g * p;
- rgb.b = color[c1].b * q + color[c2].b * p;
- cairo_set_source_rgb(cr, rgb.r, rgb.g, rgb.b);
- cairo_rectangle(cr, 0, 0, window->w, window->h);
- cairo_fill(cr);
- return true;
-}
-
-bool bg_rect_unload (s_sequence *seq)
-{
- (void) seq;
- return true;
-}
diff --git a/libkc3_window/cairo/demo/bg_rect.h b/libkc3_window/cairo/demo/bg_rect.h
deleted file mode 100644
index 144f39d..0000000
--- a/libkc3_window/cairo/demo/bg_rect.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 BG_RECT_H
-#define BG_RECT_H
-
-#include "../types.h"
-
-bool bg_rect_load (s_sequence *seq);
-bool bg_rect_render (s_sequence *seq);
-bool bg_rect_unload (s_sequence *seq);
-
-#endif /* BG_RECT_H */
diff --git a/libkc3_window/cairo/demo/configure b/libkc3_window/cairo/demo/configure
deleted file mode 100755
index 682e3dd..0000000
--- a/libkc3_window/cairo/demo/configure
+++ /dev/null
@@ -1,124 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-set -e
-
-echo "$PWD/configure"
-
-export SRC_TOP="$(dirname "$PWD")"
-
-CONFIG_H_PREFIX=LIBKC3_WINDOW_CAIRO_DEMO_
-
-. ../../../config.subr
-
-LIB=libkc3_window_cairo_demo.la
-LIB_ASAN=libkc3_window_cairo_demo_asan.la
-LIB_COV=libkc3_window_cairo_demo_cov.la
-LIB_DEBUG=libkc3_window_cairo_demo_debug.la
-
-echo "LIB = $LIB" >> ${CONFIG_MK}
-echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
-echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
-echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
-
-. ./sources.sh
-
-OBJECTS="$(c2ext .main.lo "$SOURCES")"
-echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
-OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
-OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
-OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
-
-# Common config for all targets
-CPPFLAGS="-I../../.. $CPPFLAGS"
-CFLAGS="$CFLAGS -W -Wall -Werror -std=c11 -pedantic -pipe"
-LDFLAGS="--shared ${LDFLAGS}"
-LIBS="$LIBS -rpath ${PREFIX}/lib"
-config_asan
-config_gnu
-config_i386
-pkg_config libbsd-overlay
-pkg_config libffi
-pkg_config libmd
-pkg_config cairo
-pkg_config xkbcommon
-config_define PREFIX "\"${PREFIX}\""
-
-# Address Sanitizer config
-CPPFLAGS_ASAN="$CPPFLAGS"
-CFLAGS_ASAN="$CFLAGS -DDEBUG -O1 -g"
-CFLAGS_ASAN="$CFLAGS_ASAN -fsanitize=address -fno-omit-frame-pointer"
-LDFLAGS_ASAN="$LDFLAGS"
-LIBS_LOCAL_ASAN="../libkc3_window_cairo_asan.la"
-LIBS_LOCAL_ASAN="$LIBS_LOCAL_ASAN ../../libkc3_window_asan.la"
-LIBS_LOCAL_ASAN="$LIBS_LOCAL_ASAN ../../../libkc3/libkc3_asan.la"
-LIBS_ASAN="$LIBS_LOCAL_ASAN $LIBS"
-
-# Coverage config
-CPPFLAGS_COV="$CPPFLAGS"
-CFLAGS_COV="$CFLAGS -DDEBUG --coverage"
-LDFLAGS_COV="$LDFLAGS"
-LIBS_LOCAL_COV="../libkc3_window_cairo_cov.la"
-LIBS_LOCAL_COV="$LIBS_LOCAL_COV ../../libkc3_window_cov.la"
-LIBS_LOCAL_COV="$LIBS_LOCAL_COV ../../../libkc3/libkc3_cov.la"
-LIBS_COV="$LIBS_LOCAL_COV $LIBS"
-
-# Debug config
-CPPFLAGS_DEBUG="$CPPFLAGS"
-CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
-LDFLAGS_DEBUG="$LDFLAGS"
-LIBS_LOCAL_DEBUG="../libkc3_window_cairo_debug.la"
-LIBS_LOCAL_DEBUG="$LIBS_LOCAL_DEBUG ../../libkc3_window_debug.la"
-LIBS_LOCAL_DEBUG="$LIBS_LOCAL_DEBUG ../../../libkc3/libkc3_debug.la"
-LIBS_DEBUG="$LIBS_LOCAL_DEBUG $LIBS"
-
-# Main config
-DEFAULT_CFLAGS="-O2 -pipe"
-if [ "x$ENV_CFLAGS" = "x" ]; then
- CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
-fi
-CFLAGS="$CFLAGS -DNDEBUG"
-LIBS_LOCAL="../libkc3_window_cairo.la"
-LIBS_LOCAL="$LIBS_LOCAL ../../libkc3_window.la"
-LIBS_LOCAL="$LIBS_LOCAL ../../../libkc3/libkc3.la"
-LIBS="$LIBS_LOCAL $LIBS"
-
-echo "LIB = $LIB" >> ${CONFIG_MK}
-echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
-echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
-echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
-echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
-echo "LIBS = $LIBS" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
-echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
-echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
-echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
-echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
-echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
-
-update_build
-update_build_lib
-
-build_lo
-build_lib
-
-update_config_mk
diff --git a/libkc3_window/cairo/demo/flies.c b/libkc3_window/cairo/demo/flies.c
deleted file mode 100644
index 455d560..0000000
--- a/libkc3_window/cairo/demo/flies.c
+++ /dev/null
@@ -1,319 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "../cairo_font.h"
-#include "../cairo_sprite.h"
-#include "../window_cairo.h"
-#include "window_cairo_demo.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_cairo_sprite g_sprite_dead_fly = {0};
-s_cairo_sprite g_sprite_fly = {0};
-static const f64 g_xy_ratio = 0.6;
-
-static void fly_init (s_map *map)
-{
- uw address[2] = { BOARD_SIZE / 2,
- 0 };
- s_array *board;
- uw *in;
- f64 *t;
- board = &map->value[0].data.array;
- in = &map->value[1].data.uw;
- t = &map->value[3].data.f64;
- array_data_set(board, address, &g_board_item_fly);
- *t = 0.0;
- (*in)++;
-}
-
-bool flies_load (s_sequence *seq)
-{
- uw address[2];
- s_array *board;
- uw i;
- uw j;
- s_map *map;
- tag_map(&seq->tag, 4);
- map = &seq->tag.data.map;
- tag_init_sym( map->key + 0, sym_1("board"));
- tag_init_array(map->value + 0, sym_1("U8[]"),
- 2, (uw[]) {BOARD_SIZE, BOARD_SIZE});
- tag_init_sym(map->key + 1, sym_1("in"));
- tag_init_uw( map->value + 1, 0);
- tag_init_sym(map->key + 2, sym_1("out"));
- tag_init_uw( map->value + 2, 0);
- tag_init_sym(map->key + 3, sym_1("t"));
- tag_init_uw( map->value + 3, 0);
- board = &map->value[0].data.array;
- array_allocate(board);
- 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)
-{
- char 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;
- cairo_t *cr;
- 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;
- cairo_text_extents_t te;
- f64 x;
- f64 y;
- s_window_cairo *window;
- window = seq->window;
- cr = window->cr;
- cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
- cairo_rectangle(cr, 0, 0, window->w, window->h);
- cairo_fill(cr);
- /* io_inspect(&seq->tag); */
- if (seq->tag.type == TAG_MAP) {
- map = &seq->tag.data.map;
- if (map->count == 4 &&
- map->value[0].type == TAG_ARRAY &&
- map->value[1].type == TAG_UW &&
- map->value[2].type == TAG_UW &&
- map->value[3].type == TAG_UW) {
- board = &map->value[0].data.array;
- fly_in = &map->value[1].data.uw;
- fly_out = &map->value[2].data.uw;
- fly_time = &map->value[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_sprite_fly.w;
- dead_fly_scale = 2.0 * board_item_w / g_sprite_dead_fly.w;
- cairo_set_source_rgb(cr, 0.6, 0.7, 0.9);
- cairo_rectangle(cr, board_x, 0, board_w, board_h);
- cairo_fill(cr);
- cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
- cairo_set_font_size(cr, board_item_h);
- cairo_set_font(cr, &g_font_courier_new);
- buf_init(&buf, false, sizeof(a), a);
- buf_write_1(&buf, "In ");
- buf_inspect_uw(&buf, fly_in);
- buf_write_u8(&buf, 0);
- cairo_text_extents(cr, buf.ptr.pchar, &te);
- y = board_h + board_item_h + te.height + te.y_bearing;
- x = board_x;
- cairo_move_to(cr, x, y);
- cairo_show_text(cr, buf.ptr.pchar);
- 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_x + board_item_w * (BOARD_SIZE / 2 + 1);
- cairo_move_to(cr, x, y);
- cairo_show_text(cr, buf.ptr.pchar);
- address[1] = 0;
- while (address[1] < BOARD_SIZE) {
- y = board_item_h * address[1];
- address[0] = 0;
- while (address[0] < BOARD_SIZE) {
- x = board_x + board_item_w * address[0];
- cairo_translate(cr, x, y);
- board_item = (u8 *) array_data(board, address);
- assert(board_item);
- switch (*board_item) {
- case BOARD_ITEM_SPACE:
- break;
- case BOARD_ITEM_BLOCK:
- cairo_set_source_rgb(cr, 0.0, 0.0, 1.0);
- cairo_rectangle(cr, 0, 0, board_item_w + 1.0,
- board_item_h + 1.0);
- cairo_fill(cr);
- break;
- case BOARD_ITEM_FLY:
- cairo_translate(cr, -board_item_w / 2.0,
- -board_item_h / 2.0);
- cairo_scale(cr, fly_scale, fly_scale);
- cairo_sprite_blit(&g_sprite_fly, 0,
- cr, 0, 0);
- 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 = arc4random();
- random_bits = 32;
- }
- 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:
- cairo_translate(cr, -board_item_w / 2.0,
- -board_item_h / 2.0);
- cairo_scale(cr, dead_fly_scale, dead_fly_scale);
- cairo_sprite_blit(&g_sprite_dead_fly, 0,
- cr, 0, 0);
- break;
- }
- cairo_identity_matrix(cr);
- address[0]++;
- }
- address[1]++;
- }
- }
- }
- return true;
-}
-
-bool flies_unload (s_sequence *seq)
-{
- (void) seq;
- return true;
-}
diff --git a/libkc3_window/cairo/demo/flies.h b/libkc3_window/cairo/demo/flies.h
deleted file mode 100644
index 410e147..0000000
--- a/libkc3_window/cairo/demo/flies.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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"
-
-extern s_cairo_sprite g_sprite_dead_fly;
-extern s_cairo_sprite g_sprite_fly;
-
-bool flies_load (s_sequence *seq);
-bool flies_render (s_sequence *seq);
-bool flies_unload (s_sequence *seq);
-
-#endif /* FLIES_H */
diff --git a/libkc3_window/cairo/demo/lightspeed.c b/libkc3_window/cairo/demo/lightspeed.c
deleted file mode 100644
index 6eeaffe..0000000
--- a/libkc3_window/cairo/demo/lightspeed.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "lightspeed.h"
-
-static void star_init (s_tag *star)
-{
- f64 x;
- f64 y;
- f64_random(&x);
- f64_random(&y);
- tag_map(star, 3);
- tag_init_sym(star->data.map.key, sym_1("speed"));
- tag_init_f64(star->data.map.value, 0.0);
- tag_init_sym(star->data.map.key + 1, sym_1("x"));
- tag_init_f64(star->data.map.value + 1, 2.0 * x - 1.0);
- tag_init_sym(star->data.map.key + 2, sym_1("y"));
- tag_init_f64(star->data.map.value + 2, 2.0 * y - 1.0);
-}
-
-static void star_render (s_tag *star, s_window_cairo *window,
- cairo_t *cr, s_sequence *seq)
-{
- f64 q;
- f64 *speed;
- f64 *x;
- f64 *y;
- (void) window;
- speed = &star->data.map.value[0].data.f64;
- x = &star->data.map.value[1].data.f64;
- y = &star->data.map.value[2].data.f64;
- cairo_set_line_width(cr, 0.004);
- cairo_set_source_rgb(cr, 1, 1, 1);
- cairo_move_to(cr, *x, *y);
- q = (1 + *speed / 20);
- cairo_line_to(cr, *x * q, *y * q);
- cairo_stroke(cr);
- 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)
-{
- uw i;
- 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)
-{
- cairo_t *cr;
- uw i;
- cairo_matrix_t matrix;
- s_window_cairo *window;
- window = seq->window;
- cr = window->cr;
- cairo_get_matrix(cr, &matrix);
- cairo_scale(cr, window->w / 2.0, window->h / 2.0);
- cairo_translate(cr, 1.0, 1.0);
- cairo_set_source_rgb(cr, 0, 0, 0);
- cairo_rectangle(cr, -1, -1, 2, 2);
- cairo_fill(cr);
- i = 0;
- while (i < LIGHTSPEED_STARS) {
- star_render(seq->tag.data.tuple.tag + i, window, cr, seq);
- i++;
- }
- cairo_set_matrix(cr, &matrix);
- return true;
-}
-
-bool lightspeed_unload (s_sequence *seq)
-{
- (void) seq;
- return true;
-}
diff --git a/libkc3_window/cairo/demo/lightspeed.h b/libkc3_window/cairo/demo/lightspeed.h
deleted file mode 100644
index efc1992..0000000
--- a/libkc3_window/cairo/demo/lightspeed.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 1000
-
-bool lightspeed_load (s_sequence *seq);
-bool lightspeed_render (s_sequence *seq);
-bool lightspeed_unload (s_sequence *seq);
-
-#endif /* LIGHTSPEED_H */
diff --git a/libkc3_window/cairo/demo/mandelbrot_f128.c b/libkc3_window/cairo/demo/mandelbrot_f128.c
deleted file mode 100644
index 21fd69d..0000000
--- a/libkc3_window/cairo/demo/mandelbrot_f128.c
+++ /dev/null
@@ -1,275 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "../cairo_text.h"
-#include "mandelbrot_f128.h"
-
-static cairo_surface_t *g_mandelbrot_f128_surface = NULL;
-
-static bool mandelbrot_f128_resize (s_sequence *seq);
-static bool mandelbrot_f128_update (s_sequence *seq);
-
-bool mandelbrot_f128_button (s_sequence *seq, u8 button, sw x, sw y)
-{
- s_map *map;
- f128 *next_x;
- f128 *next_y;
- f128 *next_z;
- s_window_cairo *win;
- assert(seq);
- win = seq->window;
- assert(win);
- 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;
- if (button == 1) {
- *next_x = *next_x + *next_z * (x - (f128) win->w / 2);
- *next_y = *next_y + *next_z * (y - (f128) win->h / 2);
- }
- else if (button == 5) {
- *next_z = *next_z * exp2l(0.5);
- }
- else if (button == 4) {
- *next_z = *next_z * exp2l(-0.5);
- }
- return true;
-}
-
-bool mandelbrot_f128_load (s_sequence *seq)
-{
- s_map *map;
- assert(seq);
- 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("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.0);
- return true;
-}
-
-bool mandelbrot_f128_render (s_sequence *seq)
-{
- cairo_t *cr;
- uw *h;
- s_map *map;
- f128 next_x;
- f128 next_y;
- f128 next_z;
- uw *w;
- s_window_cairo *win;
- f128 *x;
- f128 *y;
- f128 *z;
- assert(seq);
- win = seq->window;
- assert(win);
- cr = win->cr;
- 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("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[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 (! g_mandelbrot_f128_surface ||
- *w != win->w || *h != win->h)
- 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;
- }
- cairo_identity_matrix(cr);
- cairo_set_source_surface(cr, g_mandelbrot_f128_surface, 0, 0);
- cairo_rectangle(cr, 0, 0, win->w, win->h);
- cairo_fill(cr);
- char a[128];
- s_buf buf;
- buf_init(&buf, false, sizeof(a), a);
- buf_write_1(&buf, "x: ");
- buf_inspect_f128(&buf, &next_x);
- buf_write_u8(&buf, 0);
- cairo_text_outline(cr, 20, win->h - 100, a);
- buf_init(&buf, false, sizeof(a), a);
- buf_write_1(&buf, "y: ");
- buf_inspect_f128(&buf, &next_y);
- buf_write_u8(&buf, 0);
- cairo_text_outline(cr, 20, win->h - 80, a);
- buf_init(&buf, false, sizeof(a), a);
- buf_write_1(&buf, "z: ");
- buf_inspect_f128(&buf, &next_z);
- buf_write_u8(&buf, 0);
- cairo_text_outline(cr, 20, win->h - 60, a);
- return true;
-}
-
-static bool mandelbrot_f128_resize (s_sequence *seq)
-{
- s_window_cairo *win;
- assert(seq);
- win = seq->window;
- assert(win);
- cairo_surface_destroy(g_mandelbrot_f128_surface);
- g_mandelbrot_f128_surface =
- cairo_image_surface_create(CAIRO_FORMAT_RGB24,
- win->w, win->h);
- return true;
-}
-
-bool mandelbrot_f128_unload (s_sequence *seq)
-{
- (void) seq;
- cairo_surface_destroy(g_mandelbrot_f128_surface);
- g_mandelbrot_f128_surface = NULL;
- return true;
-}
-
-static bool mandelbrot_f128_update (s_sequence *seq)
-{
- f128 _2z_xz_y;
- f128 c_x;
- f128 c_y;
- u8 *data;
- uw i;
- uw j;
- u8 k;
- u8 level;
- s_map *map;
- f128 next_x;
- f128 next_y;
- f128 next_z;
- u8 *pix;
- uw stride;
- s_window_cairo *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;
- cairo_surface_flush(g_mandelbrot_f128_surface);
- data = cairo_image_surface_get_data(g_mandelbrot_f128_surface);
- assert(data);
- stride = cairo_image_surface_get_stride(g_mandelbrot_f128_surface);
- i = 0;
- while (i < win->h) {
- c_y = next_y + next_z * ((f128) i - win->h / 2);
- pix = data + i * stride;
- j = 0;
- while (j < win->w) {
- c_x = next_x + next_z * ((f128) 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 = 255 - k;
- /*if (k)
- printf("x %lu, y %lu, k %d, level %d", j, i, k, level);*/
- pix[0] = level;
- pix[1] = level;
- pix[2] = level;
- pix += 4;
- j++;
- }
- i++;
- }
- cairo_surface_mark_dirty(g_mandelbrot_f128_surface);
- return true;
-}
diff --git a/libkc3_window/cairo/demo/mandelbrot_f128.h b/libkc3_window/cairo/demo/mandelbrot_f128.h
deleted file mode 100644
index 3a95d69..0000000
--- a/libkc3_window/cairo/demo/mandelbrot_f128.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 MANDELBROT_F128_H
-#define MANDELBROT_F128_H
-
-#include "../types.h"
-
-bool mandelbrot_f128_button (s_sequence *seq, u8 button, sw x, sw y);
-bool mandelbrot_f128_load (s_sequence *seq);
-bool mandelbrot_f128_render (s_sequence *seq);
-bool mandelbrot_f128_unload (s_sequence *seq);
-
-#endif /* MANDELBROT_F128_H */
diff --git a/libkc3_window/cairo/demo/sources.mk b/libkc3_window/cairo/demo/sources.mk
deleted file mode 100644
index 3d8cbec..0000000
--- a/libkc3_window/cairo/demo/sources.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-# sources.mk generated by update_sources
-HEADERS = \
- "bg_rect.h" \
- "flies.h" \
- "lightspeed.h" \
- "mandelbrot_f128.h" \
- "toasters.h" \
- "window_cairo_demo.h" \
-
-SOURCES = \
- "bg_rect.c" \
- "flies.c" \
- "lightspeed.c" \
- "mandelbrot_f128.c" \
- "toasters.c" \
- "window_cairo_demo.c" \
-
diff --git a/libkc3_window/cairo/demo/sources.sh b/libkc3_window/cairo/demo/sources.sh
deleted file mode 100644
index 6cd2723..0000000
--- a/libkc3_window/cairo/demo/sources.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-# sources.sh generated by update_sources
-HEADERS='bg_rect.h flies.h lightspeed.h mandelbrot_f128.h toasters.h window_cairo_demo.h '
-SOURCES='bg_rect.c flies.c lightspeed.c mandelbrot_f128.c toasters.c window_cairo_demo.c '
diff --git a/libkc3_window/cairo/demo/toasters.c b/libkc3_window/cairo/demo/toasters.c
deleted file mode 100644
index 09efc9f..0000000
--- a/libkc3_window/cairo/demo/toasters.c
+++ /dev/null
@@ -1,242 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "../cairo_sprite.h"
-#include "toasters.h"
-
-static const f64 g_speed_x = 80.0;
-static const f64 g_speed_y = -40.0;
-s_cairo_sprite g_sprite_toast = {0};
-s_cairo_sprite g_sprite_toaster = {0};
-
-static bool toasters_render_toasters (s_list **toasters,
- s_window_cairo *window,
- cairo_t *cr,
- s_sequence *seq);
-static bool toasters_render_toasts (s_list **toasts,
- s_window_cairo *window,
- cairo_t *cr,
- s_sequence *seq);
-
-static s_tag * toast_init (s_tag *toast, f64 x, f64 y)
-{
- tag_init_map(toast, 2);
- tag_init_sym(toast->data.map.key + 0, sym_1("x"));
- tag_init_f64(toast->data.map.value + 0, x);
- tag_init_sym(toast->data.map.key + 1, sym_1("y"));
- tag_init_f64(toast->data.map.value + 1, y);
- return toast;
-}
-
-static void toast_render (s_tag *toast, s_window_cairo *window,
- cairo_t *cr, s_sequence *seq)
-{
- cairo_matrix_t matrix;
- f64 *x;
- f64 *y;
- if (toast->type == TAG_MAP) {
- x = &toast->data.map.value[0].data.f64;
- y = &toast->data.map.value[1].data.f64;
- *x -= seq->dt * g_speed_x;
- *y -= seq->dt * g_speed_y;
- if (*x < -100 || *y > window->h) {
- tag_clean(toast);
- toast->type = TAG_VOID;
- return;
- }
- cairo_get_matrix(cr, &matrix);
- cairo_translate(cr, *x, *y);
- cairo_sprite_blit(&g_sprite_toast, 0, cr, 0, 0);
- cairo_set_matrix(cr, &matrix);
- }
-}
-
-static s_tag * toaster_init (s_tag *toaster, f64 y)
-{
- tag_init_map(toaster, 2);
- tag_init_sym(toaster->data.map.key + 0, sym_1("x"));
- tag_init_f64(toaster->data.map.value + 0, -150);
- tag_init_sym(toaster->data.map.key + 1, sym_1("y"));
- tag_init_f64(toaster->data.map.value + 1, y);
- return toaster;
-}
-
-static void toaster_render (s_tag *toaster, s_window_cairo *window,
- cairo_t *cr, s_sequence *seq)
-{
- cairo_matrix_t matrix;
- f64 *x;
- f64 *y;
- if (toaster->type == TAG_MAP) {
- x = &toaster->data.map.value[0].data.f64;
- y = &toaster->data.map.value[1].data.f64;
- *x += seq->dt * g_speed_x;
- *y += seq->dt * g_speed_y;
- if (*x > window->w || *y < -200) {
- tag_clean(toaster);
- toaster->type = TAG_VOID;
- return;
- }
- cairo_get_matrix(cr, &matrix);
- cairo_translate(cr, *x, *y);
- cairo_sprite_blit(&g_sprite_toaster,
- fmod(seq->t * g_sprite_toaster.frame_count,
- g_sprite_toaster.frame_count),
- cr, 0, 0);
- cairo_set_matrix(cr, &matrix);
- }
-}
-
-bool toasters_load (s_sequence *seq)
-{
- s_map *map;
- tag_map(&seq->tag, 2);
- map = &seq->tag.data.map;
- tag_init_sym( map->key + 0, sym_1("toasters"));
- tag_init_list(map->value + 0, NULL);
- tag_init_sym( map->key + 1, sym_1("toasts"));
- tag_init_list(map->value + 1, NULL);
- return true;
-}
-
-bool toasters_render (s_sequence *seq)
-{
- cairo_t *cr;
- s_list **toasters;
- s_list **toasts;
- s_window_cairo *window;
- window = seq->window;
- cr = window->cr;
- cairo_set_source_rgb(cr, 0.7, 0.95, 1.0);
- cairo_rectangle(cr, 0, 0, window->w, window->h);
- cairo_fill(cr);
- /* io_inspect(&seq->tag); */
- if (seq->tag.type == TAG_MAP) {
- toasters = &seq->tag.data.map.value[0].data.list;
- toasts = &seq->tag.data.map.value[1].data.list;
- toasters_render_toasts(toasts, window, cr, seq);
- toasters_render_toasters(toasters, window, cr, seq);
- }
- return true;
-}
-
-bool toasters_render_toasts (s_list **toasts, s_window_cairo *window,
- cairo_t *cr, s_sequence *seq)
-{
- s_list *i;
- s_list *j;
- s_map *map;
- s_list **t = NULL;
- f64 x;
- f64 y;
- assert(toasts);
- assert(window);
- assert(cr);
- assert(seq);
- y = window->w * g_speed_y / g_speed_x - 210;
- if (*toasts && (*toasts)->tag.type == TAG_MAP) {
- t = &(*toasts)->tag.data.map.value[0].data.list;
- y = (*toasts)->tag.data.map.value[1].data.f64;
- }
- while (y < window->h - 100) {
- y += 170.0;
- *toasts = list_new_map(2, *toasts);
- map = &(*toasts)->tag.data.map;
- tag_init_sym(map->key + 0, sym_1("toasts"));
- tag_init_list(map->value + 0, NULL);
- tag_init_sym(map->key + 1, sym_1("y"));
- tag_init_f64(map->value + 1, y);
- }
- i = *toasts;
- while (i) {
- if (i->tag.type == TAG_MAP) {
- t = &i->tag.data.map.value[0].data.list;
- y = i->tag.data.map.value[1].data.f64;
- x = 0.0;
- if (*t && (*t)->tag.type == TAG_MAP)
- x = (*t)->tag.data.map.value[0].data.f64;
- if (x < window->w - 160.0) {
- *t = list_new(*t);
- toast_init(&(*t)->tag, window->w, y);
- }
- list_remove_void(t);
- j = *t;
- while (j) {
- toast_render(&j->tag, window, cr, seq);
- j = list_next(j);
- }
- }
- i = list_next(i);
- }
- return true;
-}
-
-bool toasters_render_toasters (s_list **toasters,
- s_window_cairo *window, cairo_t *cr,
- s_sequence *seq)
-{
- s_list *i;
- s_list *j;
- s_map *map;
- s_list **t = NULL;
- f64 x;
- f64 y;
- assert(toasters);
- assert(window);
- assert(cr);
- assert(seq);
- /* io_inspect_list((const s_list **) toasters); */
- y = -100.0;
- if (*toasters && (*toasters)->tag.type == TAG_MAP) {
- t = &(*toasters)->tag.data.map.value[0].data.list;
- y = (*toasters)->tag.data.map.value[1].data.f64;
- }
- while (y < window->h - window->w * g_speed_y / g_speed_x) {
- y += 170.0;
- *toasters = list_new_map(2, *toasters);
- map = &(*toasters)->tag.data.map;
- tag_init_sym(map->key + 0, sym_1("toasters"));
- tag_init_list(map->value + 0, NULL);
- tag_init_sym(map->key + 1, sym_1("y"));
- tag_init_f64(map->value + 1, y);
- }
- i = *toasters;
- while (i) {
- if (i->tag.type == TAG_MAP) {
- t = &i->tag.data.map.value[0].data.list;
- y = i->tag.data.map.value[1].data.f64;
- x = 1000.0;
- if (*t && (*t)->tag.type == TAG_MAP)
- x = (*t)->tag.data.map.value[0].data.f64;
- if (x > 60.0) {
- *t = list_new(*t);
- toaster_init(&(*t)->tag, y);
- }
- list_remove_void(t);
- j = *t;
- while (j) {
- toaster_render(&j->tag, window, cr, seq);
- j = list_next(j);
- }
- }
- i = list_next(i);
- }
- return true;
-}
-
-bool toasters_unload (s_sequence *seq)
-{
- (void) seq;
- return true;
-}
diff --git a/libkc3_window/cairo/demo/toasters.h b/libkc3_window/cairo/demo/toasters.h
deleted file mode 100644
index 4ea1fae..0000000
--- a/libkc3_window/cairo/demo/toasters.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 TOASTERS_H
-#define TOASTERS_H
-
-#include "../types.h"
-
-extern s_cairo_sprite g_sprite_toast;
-extern s_cairo_sprite g_sprite_toaster;
-
-bool toasters_load (s_sequence *seq);
-bool toasters_render (s_sequence *seq);
-bool toasters_unload (s_sequence *seq);
-
-#endif /* TOASTERS_H */
diff --git a/libkc3_window/cairo/demo/update_sources b/libkc3_window/cairo/demo/update_sources
deleted file mode 100755
index 0c17b11..0000000
--- a/libkc3_window/cairo/demo/update_sources
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-. ../../../config.subr
-
-echo "$PWD/update_sources"
-
-echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
-echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
-
-HEADERS="$(ls *.h | grep -v '^config.h$')"
-sources HEADERS "$HEADERS"
-
-SOURCES="$(ls *.c)"
-sources SOURCES "$SOURCES"
-
-update_sources_mk
-update_sources_sh
diff --git a/libkc3_window/cairo/demo/window_cairo_demo.c b/libkc3_window/cairo/demo/window_cairo_demo.c
deleted file mode 100644
index b91f9ba..0000000
--- a/libkc3_window/cairo/demo/window_cairo_demo.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <stdlib.h>
-#include <libkc3/kc3.h>
-#include <xkbcommon/xkbcommon.h>
-#include "../../window.h"
-#include "../cairo_font.h"
-#include "../cairo_sprite.h"
-#include "../cairo_text.h"
-#include "../window_cairo.h"
-#include "window_cairo_demo.h"
-#include "bg_rect.h"
-#include "lightspeed.h"
-#include "toasters.h"
-#include "flies.h"
-#include "mandelbrot_f128.h"
-
-s_cairo_font g_font_computer_modern = {0};
-s_cairo_font g_font_courier_new = {0};
-
-bool window_cairo_demo_button (s_window_cairo *window, u8 button,
- sw x, sw y)
-{
- assert(window);
- (void) window;
- io_write_1("kc3_window_cairo_demo_button: ");
- io_inspect_u8(&button);
- io_write_1(" (");
- io_inspect_sw(&x);
- io_write_1(", ");
- io_inspect_sw(&y);
- io_puts(")");
- if (window->seq->button &&
- ! window->seq->button(window->seq, button, x, y))
- return false;
- return true;
-}
-
-bool window_cairo_demo_key (s_window_cairo *window, uw keysym)
-{
- char keysym_name[64];
- assert(window);
- (void) window;
- switch (keysym) {
- case XKB_KEY_Escape:
- case XKB_KEY_q:
- g_kc3_exit_code = 0;
- return false;
- case XKB_KEY_Left:
- if (! window_set_sequence_pos((s_window *) window,
- (window->sequence_pos +
- window->sequence_count - 1) %
- window->sequence_count))
- return false;
- break;
- case XKB_KEY_Right:
- if (! window_set_sequence_pos((s_window *) window,
- (window->sequence_pos + 1) %
- window->sequence_count))
- return false;
- break;
- default:
- xkb_keysym_get_name(keysym, keysym_name, sizeof(keysym_name));
- io_write_1("kc3_window_cairo_demo_key: ");
- io_inspect_uw(&keysym);
- io_write_1(" ");
- io_puts(keysym_name);
- }
- return true;
-}
-
-bool window_cairo_demo_load (s_window_cairo *window)
-{
- assert(window);
- if (window->sequence_count != WINDOW_CAIRO_DEMO_SEQUENCE_COUNT) {
- err_write_1("window_cairo_demo_load: window->sequence_count = ");
- err_inspect_uw(&window->sequence_count);
- err_write_1("\n");
- assert(window->sequence_count == WINDOW_CAIRO_DEMO_SEQUENCE_COUNT);
- return false;
- }
- if (! cairo_font_init(&g_font_courier_new,
- "fonts/Courier New/Courier New.ttf"))
- return false;
- sequence_init(window->sequence, 8.0, "01. Background rectangles",
- bg_rect_load, bg_rect_render, bg_rect_unload, window);
- sequence_init(window->sequence + 1, 20.0, "02. Lightspeed",
- lightspeed_load, lightspeed_render, lightspeed_unload,
- window);
- if (! cairo_sprite_init(&g_sprite_toaster, "img/flaps.png",
- 4, 1, 4))
- return false;
- if (! cairo_sprite_init(&g_sprite_toast, "img/toast.png",
- 1, 1, 1))
- return false;
- sequence_init(window->sequence + 2, 60.0, "03. Toasters",
- toasters_load, toasters_render, toasters_unload,
- window);
- if (! cairo_sprite_init(&g_sprite_fly, "img/fly-noto.png",
- 1, 1, 1))
- return false;
- if (! cairo_sprite_init(&g_sprite_dead_fly, "img/fly-dead.png",
- 1, 1, 1))
- return false;
- sequence_init(window->sequence + 3, 60.0, "04. Flies",
- flies_load, flies_render, flies_unload, window);
- sequence_init(window->sequence + 4, 3600.0, "05. Mandelbrot (f128)",
- mandelbrot_f128_load, mandelbrot_f128_render,
- mandelbrot_f128_unload, window);
- window->sequence[4].button = mandelbrot_f128_button;
- window_set_sequence_pos((s_window *) window, 0);
- return true;
-}
-
-bool window_cairo_demo_render (s_window_cairo *window)
-{
- cairo_t *cr;
- s_sequence *seq;
- cairo_text_extents_t te;
- assert(window);
- cr = window->cr;
- assert(cr);
- if (! window_animate((s_window *) window))
- return false;
- seq = window->sequence + window->sequence_pos;
- if (! seq->render(seq))
- return false;
- /* text */
- cairo_identity_matrix(cr);
- cairo_set_font_size(cr, 20);
- cairo_set_font(cr, &g_font_courier_new);
- cairo_text_extents(cr, seq->title, &te);
- cairo_text_outline(cr, 20.0, window->h - te.height - te.y_bearing - 20,
- seq->title);
- /* progress bar */
- cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
- cairo_rectangle(cr, 19, window->h - 12,
- (window->w - 40.0) * seq->t / seq->duration + 2,
- 4);
- cairo_fill(cr);
- cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
- cairo_rectangle(cr, 20, window->h - 11,
- (window->w - 40.0) * seq->t / seq->duration,
- 2);
- cairo_fill(cr);
- /* fps */
- char fps[32];
- snprintf(fps, sizeof(fps), "%f", (f64) seq->frame / seq->t);
- cairo_text_extents(cr, fps, &te);
- cairo_text_outline(cr, 20.0, 20.0 + te.height, fps);
- return true;
-}
-
-bool window_cairo_demo_resize (s_window_cairo *window,
- uw w, uw h)
-{
- assert(window);
- (void) window;
- (void) w;
- (void) h;
- return true;
-}
-
-void window_cairo_demo_unload (s_window_cairo *window)
-{
- assert(window);
- (void) window;
- cairo_font_clean(&g_font_courier_new);
- cairo_sprite_clean(&g_sprite_toaster);
- cairo_sprite_clean(&g_sprite_toast);
- cairo_sprite_clean(&g_sprite_fly);
- cairo_sprite_clean(&g_sprite_dead_fly);
-}
diff --git a/libkc3_window/cairo/demo/window_cairo_demo.h b/libkc3_window/cairo/demo/window_cairo_demo.h
deleted file mode 100644
index 8c48aa7..0000000
--- a/libkc3_window/cairo/demo/window_cairo_demo.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_DEMO_H
-#define LIBKC3_WINDOW_CAIRO_DEMO_H
-
-#include "../types.h"
-
-#define WINDOW_CAIRO_DEMO_SEQUENCE_COUNT 5
-
-extern s_cairo_font g_font_computer_modern;
-extern s_cairo_font g_font_courier_new;
-
-bool window_cairo_demo_button (s_window_cairo *window, u8 button,
- sw x, sw y);
-bool window_cairo_demo_key (s_window_cairo *window, uw keysym);
-bool window_cairo_demo_load (s_window_cairo *window);
-bool window_cairo_demo_render (s_window_cairo *window);
-bool window_cairo_demo_resize (s_window_cairo *window, uw w, uw h);
-void window_cairo_demo_unload (s_window_cairo *window);
-
-#endif /* LIBKC3_WINDOW_CAIRO_DEMO_H */
diff --git a/libkc3_window/cairo/quartz/Makefile b/libkc3_window/cairo/quartz/Makefile
deleted file mode 100644
index c1434e4..0000000
--- a/libkc3_window/cairo/quartz/Makefile
+++ /dev/null
@@ -1,85 +0,0 @@
-## kc3
-## Copyright 2022-2024 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.
-
-CLEANFILES = *.a *.gcno *.la .libs *.lo *.o
-
-CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
-
-CLEANFILES += ${CLEANFILES_COV}
-
-DISTCLEANFILES = ${CLEANFILES} config.h config.mk
-
-build: libc3_window_cairo_quartz.la
- ${MAKE} -C demo build
-
-all:
- ${MAKE} build
- if ${HAVE_GCOV}; then ${MAKE} cov; fi
- ${MAKE} debug
- if ${HAVE_ASAN}; then ${MAKE} asan; fi
-
-asan: libc3_window_cairo_quartz_asan.la
- ${MAKE} -C demo asan
-
-clean:
- rm -rf ${CLEANFILES}
- ${MAKE} -C demo clean
-
-clean_cov:
- rm -rf ${CLEANFILES_COV}
- ${MAKE} -C demo clean_cov
-
-cov: libc3_window_cairo_quartz_cov.la
- ${MAKE} -C demo cov
-
-debug: libc3_window_cairo_quartz_debug.la
- ${MAKE} -C demo debug
-
-demo: build
- ${MAKE} -C demo demo
-
-demo_debug: debug
- ${MAKE} -C demo demo_debug
-
-distclean:
- rm -rf ${DISTCLEANFILES}
- ${MAKE} -C demo distclean
-
-gdb_demo: debug
- ${MAKE} -C demo gdb_demo
-
-lldb_demo: debug
- ${MAKE} -C demo lldb_demo
-
-test: build
- ${MAKE} -C demo test
-
-update_sources:
- ./update_sources
-
-.PHONY: \
- all \
- asan \
- build \
- clean \
- cov \
- debug \
- demo \
- distclean \
- gdb_demo \
- gen \
- install \
- test \
- update_sources
-
-include config.mk
-include sources.mk
diff --git a/libkc3_window/cairo/quartz/configure b/libkc3_window/cairo/quartz/configure
deleted file mode 100755
index bc1d544..0000000
--- a/libkc3_window/cairo/quartz/configure
+++ /dev/null
@@ -1,125 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-set -e
-
-echo "$PWD/configure"
-
-export SRC_TOP="$(dirname "$PWD")"
-
-. ../../../config.subr
-
-LIB=libkc3_window_cairo_quartz.la
-LIB_ASAN=libkc3_window_cairo_quartz_asan.la
-LIB_COV=libkc3_window_cairo_quartz_cov.la
-LIB_DEBUG=libkc3_window_cairo_quartz_debug.la
-
-echo "LIB = $LIB" >> ${CONFIG_MK}
-echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
-echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
-echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
-
-. ./sources.sh
-
-OBJECTS="$(c2ext .main.lo "$SOURCES")"
-OBJECTS="$OBJECTS $(objc2ext .main.lo "$OBJC_SOURCES")"
-echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
-
-OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
-OBJECTS_ASAN="$OBJECTS_ASAN $(objc2ext .asan.lo "$OBJC_SOURCES")"
-echo "OBJECTS_ASAN = $OBJECTS_ASAN" >> ${CONFIG_MK}
-
-OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
-OBJECTS_COV="$OBJECTS_COV $(objc2ext .cov.lo "$OBJC_SOURCES")"
-echo "OBJECTS_COV = $OBJECTS_COV" >> ${CONFIG_MK}
-
-OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
-OBJECTS_DEBUG="$OBJECTS_DEBUG $(objc2ext .debug.lo "$OBJC_SOURCES")"
-echo "OBJECTS_DEBUG = $OBJECTS_DEBUG" >> ${CONFIG_MK}
-
-# Common config for all targets
-CPPFLAGS="$CPPFLAGS -I../../.."
-CFLAGS="$CFLAGS -W -Wall -Werror -std=c11 -pedantic -pipe"
-OBJCFLAGS="$CFLAGS -W -Wall -Werror"
-LDFLAGS="--shared $LDFLAGS"
-LIBS="$LIBS"
-config_asan
-config_gnu
-config_i386
-pkg_config cairo
-pkg_config cairo-ft
-config_lib COCOA -framework Cocoa
-pkg_config libffi
-pkg_config libmd
-pkg_config xkbcommon
-
-# Asan config
-CPPFLAGS_ASAN="$CPPFLAGS"
-CFLAGS_ASAN="$CFLAGS -fsanitize=address -O1 -fno-omit-frame-pointer -g"
-LDFLAGS_ASAN="$LDFLAGS"
-LOCAL_LIBS_ASAN="../libkc3_window_cairo_asan.la"
-LIBS_ASAN="$LOCAL_LIBS_ASAN $LIBS"
-
-# Coverage config
-CPPFLAGS_COV="$CPPFLAGS"
-CFLAGS_COV="$CFLAGS -ftest-coverage -fprofile-arcs -fprofile-generate"
-LDFLAGS_COV="$LDFLAGS --coverage"
-LOCAL_LIBS_COV="../libkc3_window_cairo_cov.la"
-LIBS_COV="$LOCAL_LIBS_COV $LIBS"
-
-# Debug config
-CPPFLAGS_DEBUG="$CPPFLAGS"
-CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
-LDFLAGS_DEBUG="$LDFLAGS"
-LOCAL_LIBS_DEBUG="../libkc3_window_cairo_debug.la"
-LIBS_DEBUG="$LOCAL_LIBS_DEBUG $LIBS"
-
-# Main config
-DEFAULT_CFLAGS="-O2 -fPIC"
-if [ "x$ENV_CFLAGS" = "x" ]; then
- CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
-fi
-CFLAGS="$CFLAGS -DNDEBUG"
-LOCAL_LIBS="../libkc3_window_cairo.la"
-LIBS="$LOCAL_LIBS $LIBS"
-
-echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
-echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
-echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
-echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
-echo "LIBS = $LIBS" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
-echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
-echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
-
-update_build
-update_build_objc
-update_build_lib
-
-build_lo
-build_lo_objc
-build_lib
-
-update_config_mk
-env_reset
-
-config_subdirs demo
diff --git a/libkc3_window/cairo/quartz/demo.xcodeproj/project.pbxproj b/libkc3_window/cairo/quartz/demo.xcodeproj/project.pbxproj
deleted file mode 100644
index ac58d89..0000000
--- a/libkc3_window/cairo/quartz/demo.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,410 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 56;
- objects = {
-
-/* Begin PBXBuildFile section */
- 2A5416E32B03D3E100E42968 /* c3_window_cairo_quartz_demo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5416E02B03D3E100E42968 /* c3_window_cairo_quartz_demo.swift */; };
- 2A5416F02B03E86C00E42968 /* c3_window_cairo_quartz_demo_bridging_header.h in Sources */ = {isa = PBXBuildFile; fileRef = 2A5416E12B03D3E100E42968 /* c3_window_cairo_quartz_demo_bridging_header.h */; };
- 2A5416F12B03E86C00E42968 /* content_view.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5416E52B03D43200E42968 /* content_view.swift */; };
- 2A5416F22B03E86C00E42968 /* custom_cairo_swiftui_view.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5416E62B03D43200E42968 /* custom_cairo_swiftui_view.swift */; };
- 2A5416F32B03E86C00E42968 /* custom_cairo_view.h in Sources */ = {isa = PBXBuildFile; fileRef = 2A5416E72B03D43200E42968 /* custom_cairo_view.h */; };
- 2A5416F42B03E86C00E42968 /* custom_cairo_view.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A5416E42B03D43200E42968 /* custom_cairo_view.m */; };
- 2A5416F92B03E88E00E42968 /* libc3_window_cairo_quartz.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A5416F82B03E88E00E42968 /* libc3_window_cairo_quartz.0.dylib */; };
- 2A5416FB2B03E95B00E42968 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2A5416FA2B03E95B00E42968 /* Assets.xcassets */; };
- 2A5416FC2B03F73D00E42968 /* libc3_window_cairo_quartz.0.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 2A5416F82B03E88E00E42968 /* libc3_window_cairo_quartz.0.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
- 2A5417002B0403FB00E42968 /* Preview Content in Resources */ = {isa = PBXBuildFile; fileRef = 2A5416FE2B0403FB00E42968 /* Preview Content */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXCopyFilesBuildPhase section */
- 2A5416FD2B03F73D00E42968 /* Embed Libraries */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 2147483647;
- dstPath = "";
- dstSubfolderSpec = 10;
- files = (
- 2A5416FC2B03F73D00E42968 /* libc3_window_cairo_quartz.0.dylib in Embed Libraries */,
- );
- name = "Embed Libraries";
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXCopyFilesBuildPhase section */
-
-/* Begin PBXFileReference section */
- 2A5416C32B038F6100E42968 /* c3_window_cairo_quartz_demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = c3_window_cairo_quartz_demo.app; sourceTree = BUILT_PRODUCTS_DIR; };
- 2A5416E02B03D3E100E42968 /* c3_window_cairo_quartz_demo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = c3_window_cairo_quartz_demo.swift; path = demo/c3_window_cairo_quartz_demo.swift; sourceTree = "<group>"; };
- 2A5416E12B03D3E100E42968 /* c3_window_cairo_quartz_demo_bridging_header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = c3_window_cairo_quartz_demo_bridging_header.h; path = demo/c3_window_cairo_quartz_demo_bridging_header.h; sourceTree = "<group>"; };
- 2A5416E22B03D3E100E42968 /* c3_window_cairo_quartz_demo.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; name = c3_window_cairo_quartz_demo.entitlements; path = demo/c3_window_cairo_quartz_demo.entitlements; sourceTree = "<group>"; };
- 2A5416E42B03D43200E42968 /* custom_cairo_view.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = custom_cairo_view.m; sourceTree = "<group>"; };
- 2A5416E52B03D43200E42968 /* content_view.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = content_view.swift; sourceTree = "<group>"; };
- 2A5416E62B03D43200E42968 /* custom_cairo_swiftui_view.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = custom_cairo_swiftui_view.swift; sourceTree = "<group>"; };
- 2A5416E72B03D43200E42968 /* custom_cairo_view.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = custom_cairo_view.h; sourceTree = "<group>"; };
- 2A5416F82B03E88E00E42968 /* libc3_window_cairo_quartz.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libc3_window_cairo_quartz.0.dylib; path = .libs/libc3_window_cairo_quartz.0.dylib; sourceTree = "<group>"; };
- 2A5416FA2B03E95B00E42968 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = demo/Assets.xcassets; sourceTree = "<group>"; };
- 2A5416FE2B0403FB00E42968 /* Preview Content */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "Preview Content"; path = "demo/Preview Content"; sourceTree = "<group>"; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
- 2A5416C02B038F6100E42968 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 2A5416F92B03E88E00E42968 /* libc3_window_cairo_quartz.0.dylib in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- 2A5416BA2B038F6100E42968 = {
- isa = PBXGroup;
- children = (
- 2A5416FA2B03E95B00E42968 /* Assets.xcassets */,
- 2A5416FE2B0403FB00E42968 /* Preview Content */,
- 2A5416E12B03D3E100E42968 /* c3_window_cairo_quartz_demo_bridging_header.h */,
- 2A5416E52B03D43200E42968 /* content_view.swift */,
- 2A5416E62B03D43200E42968 /* custom_cairo_swiftui_view.swift */,
- 2A5416E72B03D43200E42968 /* custom_cairo_view.h */,
- 2A5416E42B03D43200E42968 /* custom_cairo_view.m */,
- 2A5416E22B03D3E100E42968 /* c3_window_cairo_quartz_demo.entitlements */,
- 2A5416E02B03D3E100E42968 /* c3_window_cairo_quartz_demo.swift */,
- 2A5416C42B038F6100E42968 /* Products */,
- 2A5416DD2B03B3C900E42968 /* Frameworks */,
- );
- sourceTree = "<group>";
- };
- 2A5416C42B038F6100E42968 /* Products */ = {
- isa = PBXGroup;
- children = (
- 2A5416C32B038F6100E42968 /* c3_window_cairo_quartz_demo.app */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- 2A5416DD2B03B3C900E42968 /* Frameworks */ = {
- isa = PBXGroup;
- children = (
- 2A5416F82B03E88E00E42968 /* libc3_window_cairo_quartz.0.dylib */,
- );
- name = Frameworks;
- sourceTree = "<group>";
- };
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
- 2A5416C22B038F6100E42968 /* c3_window_cairo_quartz_demo */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 2A5416D22B038F6200E42968 /* Build configuration list for PBXNativeTarget "c3_window_cairo_quartz_demo" */;
- buildPhases = (
- 2A5416BF2B038F6100E42968 /* Sources */,
- 2A5416C02B038F6100E42968 /* Frameworks */,
- 2A5416C12B038F6100E42968 /* Resources */,
- 2A5416FD2B03F73D00E42968 /* Embed Libraries */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = c3_window_cairo_quartz_demo;
- productName = libc3_window_cairo_quartz;
- productReference = 2A5416C32B038F6100E42968 /* c3_window_cairo_quartz_demo.app */;
- productType = "com.apple.product-type.application";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- 2A5416BB2B038F6100E42968 /* Project object */ = {
- isa = PBXProject;
- attributes = {
- BuildIndependentTargetsInParallel = 1;
- LastSwiftUpdateCheck = 1500;
- LastUpgradeCheck = 1500;
- TargetAttributes = {
- 2A5416C22B038F6100E42968 = {
- CreatedOnToolsVersion = 15.0.1;
- LastSwiftMigration = 1500;
- };
- };
- };
- buildConfigurationList = 2A5416BE2B038F6100E42968 /* Build configuration list for PBXProject "demo" */;
- compatibilityVersion = "Xcode 14.0";
- developmentRegion = en;
- hasScannedForEncodings = 0;
- knownRegions = (
- en,
- Base,
- );
- mainGroup = 2A5416BA2B038F6100E42968;
- productRefGroup = 2A5416C42B038F6100E42968 /* Products */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- 2A5416C22B038F6100E42968 /* c3_window_cairo_quartz_demo */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
- 2A5416C12B038F6100E42968 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 2A5417002B0403FB00E42968 /* Preview Content in Resources */,
- 2A5416FB2B03E95B00E42968 /* Assets.xcassets in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
- 2A5416BF2B038F6100E42968 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 2A5416F02B03E86C00E42968 /* c3_window_cairo_quartz_demo_bridging_header.h in Sources */,
- 2A5416F12B03E86C00E42968 /* content_view.swift in Sources */,
- 2A5416F22B03E86C00E42968 /* custom_cairo_swiftui_view.swift in Sources */,
- 2A5416F32B03E86C00E42968 /* custom_cairo_view.h in Sources */,
- 2A5416F42B03E86C00E42968 /* custom_cairo_view.m in Sources */,
- 2A5416E32B03D3E100E42968 /* c3_window_cairo_quartz_demo.swift in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin XCBuildConfiguration section */
- 2A5416D02B038F6200E42968 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_ENABLE_OBJC_WEAK = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- COPY_PHASE_STRIP = NO;
- DEBUG_INFORMATION_FORMAT = dwarf;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- ENABLE_TESTABILITY = YES;
- ENABLE_USER_SCRIPT_SANDBOXING = YES;
- GCC_C_LANGUAGE_STANDARD = gnu17;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
- MTL_FAST_MATH = YES;
- ONLY_ACTIVE_ARCH = YES;
- SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
- SWIFT_OPTIMIZATION_LEVEL = "-Onone";
- };
- name = Debug;
- };
- 2A5416D12B038F6200E42968 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_ENABLE_OBJC_WEAK = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- COPY_PHASE_STRIP = NO;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- ENABLE_NS_ASSERTIONS = NO;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- ENABLE_USER_SCRIPT_SANDBOXING = YES;
- GCC_C_LANGUAGE_STANDARD = gnu17;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MTL_ENABLE_DEBUG_INFO = NO;
- MTL_FAST_MATH = YES;
- SWIFT_COMPILATION_MODE = wholemodule;
- };
- name = Release;
- };
- 2A5416D32B038F6200E42968 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- CLANG_ENABLE_MODULES = YES;
- CODE_SIGN_ENTITLEMENTS = demo/c3_window_cairo_quartz_demo.entitlements;
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
- DEVELOPMENT_ASSET_PATHS = demo;
- DEVELOPMENT_TEAM = W4AD54MQ5Q;
- ENABLE_PREVIEWS = YES;
- GENERATE_INFOPLIST_FILE = YES;
- HEADER_SEARCH_PATHS = /opt/homebrew/include;
- "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
- "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
- "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
- "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
- "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
- "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
- "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
- "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
- INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
- INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
- IPHONEOS_DEPLOYMENT_TARGET = 17.0;
- LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
- "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
- LIBRARY_SEARCH_PATHS = (
- /opt/homebrew/lib,
- /opt/homebrew/Cellar/cairo/1.18.0/lib,
- "$(PROJECT_DIR)/.libs",
- );
- MACOSX_DEPLOYMENT_TARGET = 14.0;
- MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = "kmx.io.c3-window-cairo-quartz-demo";
- PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = auto;
- STRIP_INSTALLED_PRODUCT = NO;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_OBJC_BRIDGING_HEADER = demo/c3_window_cairo_quartz_demo_bridging_header.h;
- SWIFT_OPTIMIZATION_LEVEL = "-Onone";
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- };
- name = Debug;
- };
- 2A5416D42B038F6200E42968 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- CLANG_ENABLE_MODULES = YES;
- CODE_SIGN_ENTITLEMENTS = demo/c3_window_cairo_quartz_demo.entitlements;
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
- DEVELOPMENT_ASSET_PATHS = demo;
- DEVELOPMENT_TEAM = W4AD54MQ5Q;
- ENABLE_PREVIEWS = YES;
- GENERATE_INFOPLIST_FILE = YES;
- HEADER_SEARCH_PATHS = /opt/homebrew/include;
- "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
- "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
- "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
- "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
- "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
- "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
- "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
- "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
- INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
- INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
- IPHONEOS_DEPLOYMENT_TARGET = 17.0;
- LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
- "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
- LIBRARY_SEARCH_PATHS = (
- /opt/homebrew/lib,
- /opt/homebrew/Cellar/cairo/1.18.0/lib,
- "$(PROJECT_DIR)/.libs",
- );
- MACOSX_DEPLOYMENT_TARGET = 14.0;
- MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = "kmx.io.c3-window-cairo-quartz-demo";
- PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = auto;
- STRIP_INSTALLED_PRODUCT = NO;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_OBJC_BRIDGING_HEADER = demo/c3_window_cairo_quartz_demo_bridging_header.h;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- };
- name = Release;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 2A5416BE2B038F6100E42968 /* Build configuration list for PBXProject "demo" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 2A5416D02B038F6200E42968 /* Debug */,
- 2A5416D12B038F6200E42968 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 2A5416D22B038F6200E42968 /* Build configuration list for PBXNativeTarget "c3_window_cairo_quartz_demo" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 2A5416D32B038F6200E42968 /* Debug */,
- 2A5416D42B038F6200E42968 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
-/* End XCConfigurationList section */
- };
- rootObject = 2A5416BB2B038F6100E42968 /* Project object */;
-}
diff --git a/libkc3_window/cairo/quartz/demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/libkc3_window/cairo/quartz/demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
deleted file mode 100644
index 919434a..0000000
--- a/libkc3_window/cairo/quartz/demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Workspace
- version = "1.0">
- <FileRef
- location = "self:">
- </FileRef>
-</Workspace>
diff --git a/libkc3_window/cairo/quartz/demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/libkc3_window/cairo/quartz/demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
deleted file mode 100644
index 18d9810..0000000
--- a/libkc3_window/cairo/quartz/demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>IDEDidComputeMac32BitWarning</key>
- <true/>
-</dict>
-</plist>
diff --git a/libkc3_window/cairo/quartz/demo.xcodeproj/project.xcworkspace/xcuserdata/thodg.xcuserdatad/UserInterfaceState.xcuserstate b/libkc3_window/cairo/quartz/demo.xcodeproj/project.xcworkspace/xcuserdata/thodg.xcuserdatad/UserInterfaceState.xcuserstate
deleted file mode 100644
index 73dbe44..0000000
Binary files a/libkc3_window/cairo/quartz/demo.xcodeproj/project.xcworkspace/xcuserdata/thodg.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ
diff --git a/libkc3_window/cairo/quartz/demo.xcodeproj/xcuserdata/thodg.xcuserdatad/xcschemes/xcschememanagement.plist b/libkc3_window/cairo/quartz/demo.xcodeproj/xcuserdata/thodg.xcuserdatad/xcschemes/xcschememanagement.plist
deleted file mode 100644
index df532c7..0000000
--- a/libkc3_window/cairo/quartz/demo.xcodeproj/xcuserdata/thodg.xcuserdatad/xcschemes/xcschememanagement.plist
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>SchemeUserState</key>
- <dict>
- <key>libc3_window_cairo_quartz.xcscheme_^#shared#^_</key>
- <dict>
- <key>orderHint</key>
- <integer>0</integer>
- </dict>
- </dict>
-</dict>
-</plist>
diff --git a/libkc3_window/cairo/quartz/demo/Assets.xcassets/AccentColor.colorset/Contents.json b/libkc3_window/cairo/quartz/demo/Assets.xcassets/AccentColor.colorset/Contents.json
deleted file mode 100644
index eb87897..0000000
--- a/libkc3_window/cairo/quartz/demo/Assets.xcassets/AccentColor.colorset/Contents.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "colors" : [
- {
- "idiom" : "universal"
- }
- ],
- "info" : {
- "author" : "xcode",
- "version" : 1
- }
-}
diff --git a/libkc3_window/cairo/quartz/demo/Assets.xcassets/AppIcon.appiconset/Contents.json b/libkc3_window/cairo/quartz/demo/Assets.xcassets/AppIcon.appiconset/Contents.json
deleted file mode 100644
index 532cd72..0000000
--- a/libkc3_window/cairo/quartz/demo/Assets.xcassets/AppIcon.appiconset/Contents.json
+++ /dev/null
@@ -1,63 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "platform" : "ios",
- "size" : "1024x1024"
- },
- {
- "idiom" : "mac",
- "scale" : "1x",
- "size" : "16x16"
- },
- {
- "idiom" : "mac",
- "scale" : "2x",
- "size" : "16x16"
- },
- {
- "idiom" : "mac",
- "scale" : "1x",
- "size" : "32x32"
- },
- {
- "idiom" : "mac",
- "scale" : "2x",
- "size" : "32x32"
- },
- {
- "idiom" : "mac",
- "scale" : "1x",
- "size" : "128x128"
- },
- {
- "idiom" : "mac",
- "scale" : "2x",
- "size" : "128x128"
- },
- {
- "idiom" : "mac",
- "scale" : "1x",
- "size" : "256x256"
- },
- {
- "idiom" : "mac",
- "scale" : "2x",
- "size" : "256x256"
- },
- {
- "idiom" : "mac",
- "scale" : "1x",
- "size" : "512x512"
- },
- {
- "idiom" : "mac",
- "scale" : "2x",
- "size" : "512x512"
- }
- ],
- "info" : {
- "author" : "xcode",
- "version" : 1
- }
-}
diff --git a/libkc3_window/cairo/quartz/demo/Assets.xcassets/Contents.json b/libkc3_window/cairo/quartz/demo/Assets.xcassets/Contents.json
deleted file mode 100644
index 73c0059..0000000
--- a/libkc3_window/cairo/quartz/demo/Assets.xcassets/Contents.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "info" : {
- "author" : "xcode",
- "version" : 1
- }
-}
diff --git a/libkc3_window/cairo/quartz/demo/Makefile b/libkc3_window/cairo/quartz/demo/Makefile
deleted file mode 100644
index d4d36bc..0000000
--- a/libkc3_window/cairo/quartz/demo/Makefile
+++ /dev/null
@@ -1,107 +0,0 @@
-## kc3
-## Copyright 2022-2024 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.
-
-CLEANFILES = *.a ${APP_PROG} ${APP_PROG_ASAN} ${APP_PROG_COV} \
- ${APP_PROG_DEBUG} ${PROG} ${PROG_ASAN} ${PROG_COV} ${PROG_DEBUG} \
- *.css *.gcno *.html *.o .libs *.lo
-
-CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
-CLEANFILES += ${CLEANFILES_COV}
-
-DISTCLEANFILES = ${CLEANFILES} config.mk
-
-IMG_SOURCES = \
- ../../../../img/flaps.png \
- ../../../../img/fly-dead.png \
- ../../../../img/fly-noto.png \
- ../../../../img/toast.png \
-
-FONT_SOURCES = \
- ../../../../fonts/Computer-Modern \
- ../../../../fonts/Courier\ New \
-
-build:
- ${MAKE} ${APP_PROG}
- ${MAKE} ${APP}/Contents/Frameworks
- rsync -aP ${FONT_SOURCES} ${APP}/Contents/fonts/
- rsync -aP ${IMG_SOURCES} ${APP}/Contents/img/
- rsync -aP --delete ../../../../lib ${APP}/Contents/
-
-all:
- ${MAKE} build
- if ${HAVE_GCOV}; then ${MAKE} cov; fi
- ${MAKE} debug
- if ${HAVE_ASAN}; then ${MAKE} asan; fi
-
-asan:
- ${MAKE} ${APP_PROG_ASAN}
- ${MAKE} ${APP_ASAN}/Contents/Frameworks
- rsync -aP ${FONT_SOURCES} ${APP_ASAN}/Contents/fonts/
- rsync -aP ${IMG_SOURCES} ${APP_ASAN}/Contents/img/
- rsync -aP --delete ../../../../lib ${APP_ASAN}/Contents/
-
-clean:
- rm -rf ${CLEANFILES}
-
-clean_cov:
- rm -rf ${CLEANFILES_COV}
-
-cov:
- ${MAKE} ${APP_PROG_COV}
- ${MAKE} ${APP_COV}/Contents/Frameworks
- rsync -aP ${FONT_SOURCES} ${APP_COV}/Contents/fonts/
- rsync -aP ${IMG_SOURCES} ${APP_COV}/Contents/img/
- rsync -aP --delete ../../../../lib ${APP_COV}/Contents/
-
-debug:
- ${MAKE} ${APP_PROG_DEBUG}
- ${MAKE} ${APP_DEBUG}/Contents/Frameworks
- rsync -aP ${FONT_SOURCES} ${APP_DEBUG}/Contents/fonts/
- rsync -aP ${IMG_SOURCES} ${APP_DEBUG}/Contents/img/
- rsync -aP --delete ../../../../lib ${APP_DEBUG}/Contents/
-
-demo: build
- time ${APP_PROG}
-
-demo_debug: debug
- time ${APP_PROG_DEBUG}
-
-distclean:
- rm -rf ${DISTCLEANFILES}
-
-gcovr:
- gcovr --gcov-executable ${GCOV} --html-details ${PROG}.html
-
-gdb_demo: debug
- if [ -f ${PROG_DEBUG}.core ]; then gdb .libs/${PROG_DEBUG} ${PROG_DEBUG}.core; else gdb .libs/${PROG_DEBUG}; fi
-
-lldb_demo: debug
- lldb ${APP_PROG_DEBUG}
-
-install:
- install -m 755 -d ${prefix}/bin
- install -m 755 ${PROG} ${prefix}/bin/${PROG}
-
-.PHONY: \
- all \
- asan \
- clean \
- clean_cov \
- cov \
- debug \
- demo \
- distclean \
- gdb_demo \
- lldb_demo
-
-include config.mk
-include sources.mk
diff --git a/libkc3_window/cairo/quartz/demo/Preview Content/Preview Assets.xcassets/Contents.json b/libkc3_window/cairo/quartz/demo/Preview Content/Preview Assets.xcassets/Contents.json
deleted file mode 100644
index 73c0059..0000000
--- a/libkc3_window/cairo/quartz/demo/Preview Content/Preview Assets.xcassets/Contents.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "info" : {
- "author" : "xcode",
- "version" : 1
- }
-}
diff --git a/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo.app/Contents/Info.plist b/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo.app/Contents/Info.plist
deleted file mode 100644
index e17dd6f..0000000
--- a/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo.app/Contents/Info.plist
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleExecutable</key>
- <string>c3_window_cairo_quartz_demo</string>
- <key>CFBundleIconFile</key>
- <string>c3</string>
- <key>CFBundleIdentifier</key>
- <string>io.kmx.c3-window-cairo-quartz-demo</string>
-</dict>
-</plist>
diff --git a/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo.app/Contents/Resources/c3.icns b/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo.app/Contents/Resources/c3.icns
deleted file mode 100644
index 377277a..0000000
Binary files a/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo.app/Contents/Resources/c3.icns and /dev/null differ
diff --git a/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo.entitlements b/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo.entitlements
deleted file mode 100644
index f2ef3ae..0000000
--- a/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo.entitlements
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>com.apple.security.app-sandbox</key>
- <true/>
- <key>com.apple.security.files.user-selected.read-only</key>
- <true/>
-</dict>
-</plist>
diff --git a/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo_asan.app/Contents/Info.plist b/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo_asan.app/Contents/Info.plist
deleted file mode 100644
index bf9ee0e..0000000
--- a/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo_asan.app/Contents/Info.plist
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleExecutable</key>
- <string>c3_window_cairo_quartz_demo_asan</string>
- <key>CFBundleIconFile</key>
- <string>c3</string>
- <key>CFBundleIdentifier</key>
- <string>io.kmx.c3-window-cairo-quartz-demo-asan</string>
-</dict>
-</plist>
diff --git a/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo_asan.app/Contents/Resources/c3.icns b/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo_asan.app/Contents/Resources/c3.icns
deleted file mode 100644
index 377277a..0000000
Binary files a/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo_asan.app/Contents/Resources/c3.icns and /dev/null differ
diff --git a/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo_cov.app/Contents/Info.plist b/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo_cov.app/Contents/Info.plist
deleted file mode 100644
index bd1c234..0000000
--- a/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo_cov.app/Contents/Info.plist
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleExecutable</key>
- <string>c3_window_cairo_quartz_demo_cov</string>
- <key>CFBundleIconFile</key>
- <string>c3</string>
- <key>CFBundleIdentifier</key>
- <string>io.kmx.c3-window-cairo-quartz-demo-cov</string>
-</dict>
-</plist>
diff --git a/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo_cov.app/Contents/Resources/c3_window_cairo_quartz_demo.icns b/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo_cov.app/Contents/Resources/c3_window_cairo_quartz_demo.icns
deleted file mode 100644
index 377277a..0000000
Binary files a/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo_cov.app/Contents/Resources/c3_window_cairo_quartz_demo.icns and /dev/null differ
diff --git a/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo_debug.app/Contents/Info.plist b/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo_debug.app/Contents/Info.plist
deleted file mode 100644
index 853f6b8..0000000
--- a/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo_debug.app/Contents/Info.plist
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleExecutable</key>
- <string>c3_window_cairo_quartz_demo_debug</string>
- <key>CFBundleIconFile</key>
- <string>c3</string>
- <key>CFBundleIdentifier</key>
- <string>io.kmx.c3-window-cairo-quartz-demo-debug</string>
-</dict>
-</plist>
diff --git a/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo_debug.app/Contents/Resources/c3.icns b/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo_debug.app/Contents/Resources/c3.icns
deleted file mode 100644
index 377277a..0000000
Binary files a/libkc3_window/cairo/quartz/demo/c3_window_cairo_quartz_demo_debug.app/Contents/Resources/c3.icns and /dev/null differ
diff --git a/libkc3_window/cairo/quartz/demo/configure b/libkc3_window/cairo/quartz/demo/configure
deleted file mode 100755
index 5debc85..0000000
--- a/libkc3_window/cairo/quartz/demo/configure
+++ /dev/null
@@ -1,227 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-set -e
-
-echo "$PWD/configure"
-
-export SRC_TOP="$(dirname "$PWD")"
-
-. ../../../../config.subr
-
-PROG=c3_window_cairo_quartz_demo
-PROG_ASAN=c3_window_cairo_quartz_demo_asan
-PROG_COV=c3_window_cairo_quartz_demo_cov
-PROG_DEBUG=c3_window_cairo_quartz_demo_debug
-
-echo "PROG = $PROG" >> ${CONFIG_MK}
-echo "PROG_ASAN = $PROG_ASAN" >> ${CONFIG_MK}
-echo "PROG_COV = $PROG_COV" >> ${CONFIG_MK}
-echo "PROG_DEBUG = $PROG_DEBUG" >> ${CONFIG_MK}
-
-APP=c3_window_cairo_quartz_demo.app
-APP_ASAN=c3_window_cairo_quartz_demo_asan.app
-APP_COV=c3_window_cairo_quartz_demo_cov.app
-APP_DEBUG=c3_window_cairo_quartz_demo_debug.app
-
-echo "APP = $APP" >> ${CONFIG_MK}
-echo "APP_ASAN = ${APP_ASAN}" >> ${CONFIG_MK}
-echo "APP_COV = ${APP_COV}" >> ${CONFIG_MK}
-echo "APP_DEBUG = ${APP_DEBUG}" >> ${CONFIG_MK}
-
-APP_PROG=${APP}/Contents/MacOS/${PROG}
-APP_PROG_ASAN=${APP_ASAN}/Contents/MacOS/${PROG_ASAN}
-APP_PROG_COV=${APP_COV}/Contents/MacOS/${PROG_COV}
-APP_PROG_DEBUG=${APP_DEBUG}/Contents/MacOS/${PROG_DEBUG}
-
-echo "APP_PROG = $APP_PROG" >> ${CONFIG_MK}
-echo "APP_PROG_ASAN = $APP_PROG_ASAN" >> ${CONFIG_MK}
-echo "APP_PROG_COV = $APP_PROG_COV" >> ${CONFIG_MK}
-echo "APP_PROG_DEBUG = $APP_PROG_DEBUG" >> ${CONFIG_MK}
-
-. ./sources.sh
-
-OBJECTS="$(c2ext .main.lo "$SOURCES")"
-echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
-
-OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
-echo "OBJECTS_ASAN = $OBJECTS_ASAN" >> ${CONFIG_MK}
-
-if $HAVE_GCOV; then
- OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
- echo "OBJECTS_COV = $OBJECTS_COV" >> ${CONFIG_MK}
-fi
-
-OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
-echo "OBJECTS_DEBUG = $OBJECTS_DEBUG" >> ${CONFIG_MK}
-
-# Common config for all targets
-CPPFLAGS="$CPPFLAGS -I../../../.."
-CFLAGS="$CFLAGS -W -Wall -Werror -std=c11 -pedantic -pipe"
-OBJCFLAGS="$CFLAGS -W -Wall -Werror"
-LDFLAGS="$LDFLAGS -framework Cocoa"
-LIBS="$LIBS"
-config_asan
-config_gnu
-config_i386
-pkg_config cairo
-pkg_config cairo-ft
-pkg_config libffi
-pkg_config libmd
-pkg_config xkbcommon
-
-# Asan config
-CPPFLAGS_ASAN="$CPPFLAGS"
-CFLAGS_ASAN="$CFLAGS -DDEBUG -O1 -g"
-CFLAGS_ASAN="$CFLAGS_ASAN -fsanitize=address -fno-omit-frame-pointer"
-LDFLAGS_ASAN="$LDFLAGS"
-LOCAL_LIBS_ASAN="../../demo/libkc3_window_cairo_demo_asan.la"
-LOCAL_LIBS_ASAN="$LOCAL_LIBS_ASAN ../libkc3_window_cairo_quartz_asan.la"
-LIBS_ASAN="$LOCAL_LIBS_ASAN $LIBS"
-
-# Coverage config
-CPPFLAGS_COV="$CPPFLAGS"
-CFLAGS_COV="$CFLAGS -DDEBUG --coverage"
-LDFLAGS_COV="$LDFLAGS"
-LOCAL_LIBS_COV="../../demo/libkc3_window_cairo_demo_cov.la"
-LOCAL_LIBS_COV="$LOCAL_LIBS_COV ../libkc3_window_cairo_quartz_cov.la"
-LIBS_COV="$LOCAL_LIBS_COV $LIBS"
-
-# Debug config
-CPPFLAGS_DEBUG="$CPPFLAGS"
-CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
-LDFLAGS_DEBUG="$LDFLAGS"
-LOCAL_LIBS_DEBUG="../../demo/libkc3_window_cairo_demo_debug.la"
-LOCAL_LIBS_DEBUG="$LOCAL_LIBS_DEBUG ../libkc3_window_cairo_quartz_debug.la"
-LIBS_DEBUG="$LOCAL_LIBS_DEBUG $LIBS"
-
-# Main config
-DEFAULT_CFLAGS="-O2 -fPIC"
-if [ "x$ENV_CFLAGS" = "x" ]; then
- CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
-fi
-CFLAGS="$CFLAGS -DNDEBUG"
-LIBKC3=../libkc3/libkc3.la
-LOCAL_LIBS="../../demo/libkc3_window_cairo_demo.la"
-LOCAL_LIBS="$LOCAL_LIBS ../libkc3_window_cairo_quartz.la"
-LIBS="$LOCAL_LIBS $LIBS"
-
-echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
-echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
-echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
-echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
-echo "LIBS = $LIBS" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
-echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
-echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
-
-update_build
-update_build_prog
-
-build_lo
-build_prog
-
-echo >> ${CONFIG_MK}
-echo "${APP_PROG}: ${PROG}" >> ${CONFIG_MK}
-echo " mkdir -p $(dirname $APP_PROG)" >> ${CONFIG_MK}
-echo " cp .libs/${PROG} ${APP_PROG}" >> ${CONFIG_MK}
-
-echo >> ${CONFIG_MK}
-echo "${APP_PROG_ASAN}: ${PROG_ASAN}" >> ${CONFIG_MK}
-echo " mkdir -p $(dirname $APP_PROG_ASAN)" >> ${CONFIG_MK}
-echo " cp .libs/${PROG_ASAN} ${APP_PROG_ASAN}" >> ${CONFIG_MK}
-
-echo >> ${CONFIG_MK}
-echo "${APP_PROG_COV}: ${PROG_COV}" >> ${CONFIG_MK}
-echo " mkdir -p $(dirname $APP_PROG_COV)" >> ${CONFIG_MK}
-echo " cp .libs/${PROG_COV} ${APP_PROG_COV}" >> ${CONFIG_MK}
-
-echo >> ${CONFIG_MK}
-echo "${APP_PROG_DEBUG}: ${PROG_DEBUG}" >> ${CONFIG_MK}
-echo " mkdir -p $(dirname $APP_PROG_DEBUG)" >> ${CONFIG_MK}
-echo " cp .libs/${PROG_DEBUG} ${APP_PROG_DEBUG}" >> ${CONFIG_MK}
-
-BUNDLE_LIBS="../../../../libkc3/.libs/libkc3.0.dylib ../../../.libs/libkc3_window.0.dylib ../../.libs/libkc3_window_cairo.0.dylib ../../demo/.libs/libkc3_window_cairo_demo.0.dylib ../.libs/libkc3_window_cairo_quartz.0.dylib"
-echo >> ${CONFIG_MK}
-echo "${APP}/Contents/Frameworks: ${BUNDLE_LIBS}" >> ${CONFIG_MK}
-echo " mkdir -p ${APP}/Contents/Frameworks" >> ${CONFIG_MK}
-echo " cp ${BUNDLE_LIBS} ${APP}/Contents/Frameworks/" >> ${CONFIG_MK}
-for BUNDLE_LIB in ${BUNDLE_LIBS}; do
- L=$(basename $BUNDLE_LIB)
- echo " install_name_tool -id @executable_path/../Frameworks/ ${APP}/Contents/Frameworks/$L" >> ${CONFIG_MK}
- echo " install_name_tool -change ${LIBDIR}/$L @executable_path/../Frameworks/$L ${APP}/Contents/MacOS/${PROG}" >> ${CONFIG_MK}
- echo " DEPS=\$\$(otool -L '${BUNDLE_LIB}' | awk '/^\t.+(\/usr\/lib|\/System)/ { next } /^\t/ { print \$\$1 }'); for DEP in \$\${DEPS}; do D=\$\$(basename \"\$\${DEP}\"); if [ -f ${APP}/Contents/Frameworks/\$\$D ]; then install_name_tool -change \$\${DEP} @executable_path/../Frameworks/\$\$D ${APP}/Contents/Frameworks/$L; fi; done" >> ${CONFIG_MK}
-done
-echo >> ${CONFIG_MK}
-echo ".PHONY: \\" >> ${CONFIG_MK}
-echo " ${APP}/Contents/Frameworks \\" >> ${CONFIG_MK}
-echo " ${APP_PROG}" >> ${CONFIG_MK}
-
-BUNDLE_LIBS_ASAN="../../../../libkc3/.libs/libkc3_asan.0.dylib ../../../.libs/libkc3_window_asan.0.dylib ../../.libs/libkc3_window_cairo_asan.0.dylib ../../demo/.libs/libkc3_window_cairo_demo_asan.0.dylib ../.libs/libkc3_window_cairo_quartz_asan.0.dylib"
-echo >> ${CONFIG_MK}
-echo "${APP_ASAN}/Contents/Frameworks: ${BUNDLE_LIBS_ASAN}" >> ${CONFIG_MK}
-echo " mkdir -p ${APP_ASAN}/Contents/Frameworks" >> ${CONFIG_MK}
-echo " cp ${BUNDLE_LIBS_ASAN} ${APP_ASAN}/Contents/Frameworks/" >> ${CONFIG_MK}
-for BUNDLE_LIB in ${BUNDLE_LIBS_ASAN}; do
- L=$(basename $BUNDLE_LIB)
- echo " install_name_tool -id @executable_path/../Frameworks/ ${APP_ASAN}/Contents/Frameworks/$L" >> ${CONFIG_MK}
- echo " install_name_tool -change ${LIBDIR}/$L @executable_path/../Frameworks/$L ${APP_ASAN}/Contents/MacOS/${PROG_ASAN}" >> ${CONFIG_MK}
- echo " DEPS=\$\$(otool -L '${BUNDLE_LIB}' | awk '/^\t.+(\/usr\/lib|\/System)/ { next } /^\t/ { print \$\$1 }'); for DEP in \$\${DEPS}; do D=\$\$(basename \"\$\${DEP}\"); if [ -f ${APP_ASAN}/Contents/Frameworks/\$\$D ]; then install_name_tool -change \$\${DEP} @executable_path/../Frameworks/\$\$D ${APP_ASAN}/Contents/Frameworks/$L; fi; done" >> ${CONFIG_MK}
-done
-echo >> ${CONFIG_MK}
-echo ".PHONY: \\" >> ${CONFIG_MK}
-echo " ${APP_ASAN}/Contents/Frameworks \\" >> ${CONFIG_MK}
-echo " ${APP_PROG_ASAN}" >> ${CONFIG_MK}
-
-BUNDLE_LIBS_COV="../../../../libkc3/.libs/libkc3_cov.0.dylib ../../../.libs/libkc3_window_cov.0.dylib ../../.libs/libkc3_window_cairo_cov.0.dylib ../../demo/.libs/libkc3_window_cairo_demo_cov.0.dylib ../.libs/libkc3_window_cairo_quartz_cov.0.dylib"
-echo >> ${CONFIG_MK}
-echo "${APP_COV}/Contents/Frameworks: ${BUNDLE_LIBS_COV}" >> ${CONFIG_MK}
-echo " mkdir -p ${APP_COV}/Contents/Frameworks" >> ${CONFIG_MK}
-echo " cp ${BUNDLE_LIBS_COV} ${APP_COV}/Contents/Frameworks/" >> ${CONFIG_MK}
-for BUNDLE_LIB in ${BUNDLE_LIBS_COV}; do
- L=$(basename $BUNDLE_LIB)
- echo " install_name_tool -id @executable_path/../Frameworks/ ${APP_COV}/Contents/Frameworks/$L" >> ${CONFIG_MK}
- echo " install_name_tool -change ${LIBDIR}/$L @executable_path/../Frameworks/$L ${APP_COV}/Contents/MacOS/${PROG}" >> ${CONFIG_MK}
- echo " DEPS=\$\$(otool -L '${BUNDLE_LIB}' | awk '/^\t.+(\/usr\/lib|\/System)/ { next } /^\t/ { print \$\$1 }'); for DEP in \$\${DEPS}; do D=\$\$(basename \"\$\${DEP}\"); if [ -f ${APP_COV}/Contents/Frameworks/\$\$D ]; then install_name_tool -change \$\${DEP} @executable_path/../Frameworks/\$\$D ${APP_COV}/Contents/Frameworks/$L; fi; done" >> ${CONFIG_MK}
-done
-echo >> ${CONFIG_MK}
-echo ".PHONY: \\" >> ${CONFIG_MK}
-echo " ${APP_COV}/Contents/Frameworks \\" >> ${CONFIG_MK}
-echo " ${APP_PROG}" >> ${CONFIG_MK}
-
-BUNDLE_LIBS_DEBUG="../../../../libkc3/.libs/libkc3_debug.0.dylib ../../../.libs/libkc3_window_debug.0.dylib ../../.libs/libkc3_window_cairo_debug.0.dylib ../../demo/.libs/libkc3_window_cairo_demo_debug.0.dylib ../.libs/libkc3_window_cairo_quartz_debug.0.dylib"
-echo >> ${CONFIG_MK}
-echo "${APP_DEBUG}/Contents/Frameworks: ${BUNDLE_LIBS_DEBUG}" >> ${CONFIG_MK}
-echo " mkdir -p ${APP_DEBUG}/Contents/Frameworks" >> ${CONFIG_MK}
-echo " cp ${BUNDLE_LIBS_DEBUG} ${APP_DEBUG}/Contents/Frameworks/" >> ${CONFIG_MK}
-for BUNDLE_LIB in ${BUNDLE_LIBS_DEBUG}; do
- L=$(basename $BUNDLE_LIB)
- echo " install_name_tool -id @executable_path/../Frameworks/ ${APP_DEBUG}/Contents/Frameworks/$L" >> ${CONFIG_MK}
- echo " install_name_tool -change ${LIBDIR}/$L @executable_path/../Frameworks/$L ${APP_DEBUG}/Contents/MacOS/${PROG_DEBUG}" >> ${CONFIG_MK}
- echo " DEPS=\$\$(otool -L '${BUNDLE_LIB}' | awk '/^\t.+(\/usr\/lib|\/System)/ { next } /^\t/ { print \$\$1 }'); for DEP in \$\${DEPS}; do D=\$\$(basename \"\$\${DEP}\"); if [ -f ${APP_DEBUG}/Contents/Frameworks/\$\$D ]; then install_name_tool -change \$\${DEP} @executable_path/../Frameworks/\$\$D ${APP_DEBUG}/Contents/Frameworks/$L; fi; done" >> ${CONFIG_MK}
-done
-echo >> ${CONFIG_MK}
-echo ".PHONY: \\" >> ${CONFIG_MK}
-echo " ${APP_DEBUG}/Contents/Frameworks \\" >> ${CONFIG_MK}
-echo " ${APP_PROG_DEBUG}" >> ${CONFIG_MK}
-
-update_config_mk
diff --git a/libkc3_window/cairo/quartz/demo/demo.xcodeproj/project.pbxproj b/libkc3_window/cairo/quartz/demo/demo.xcodeproj/project.pbxproj
deleted file mode 100644
index 1eedaf0..0000000
--- a/libkc3_window/cairo/quartz/demo/demo.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,354 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 56;
- objects = {
-
-/* Begin PBXBuildFile section */
- 2A54171E2B052C0300E42968 /* c3_window_cairo_quartz_demo.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A54171D2B052C0300E42968 /* c3_window_cairo_quartz_demo.c */; };
- 2A5417202B052C6600E42968 /* libc3_window_cairo_quartz.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A54171F2B052C6600E42968 /* libc3_window_cairo_quartz.0.dylib */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXFileReference section */
- 2A54170B2B0528E500E42968 /* c3_window_cairo_quartz_demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = c3_window_cairo_quartz_demo.app; sourceTree = BUILT_PRODUCTS_DIR; };
- 2A54171D2B052C0300E42968 /* c3_window_cairo_quartz_demo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = c3_window_cairo_quartz_demo.c; sourceTree = "<group>"; };
- 2A54171F2B052C6600E42968 /* libc3_window_cairo_quartz.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libc3_window_cairo_quartz.0.dylib; path = ../.libs/libc3_window_cairo_quartz.0.dylib; sourceTree = "<group>"; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
- 2A5417082B0528E500E42968 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 2A5417202B052C6600E42968 /* libc3_window_cairo_quartz.0.dylib in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- 2A5417022B0528E500E42968 = {
- isa = PBXGroup;
- children = (
- 2A54171F2B052C6600E42968 /* libc3_window_cairo_quartz.0.dylib */,
- 2A54171D2B052C0300E42968 /* c3_window_cairo_quartz_demo.c */,
- 2A54170C2B0528E500E42968 /* Products */,
- );
- sourceTree = "<group>";
- };
- 2A54170C2B0528E500E42968 /* Products */ = {
- isa = PBXGroup;
- children = (
- 2A54170B2B0528E500E42968 /* c3_window_cairo_quartz_demo.app */,
- );
- name = Products;
- sourceTree = "<group>";
- };
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
- 2A54170A2B0528E500E42968 /* c3_window_cairo_quartz_demo */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 2A54171A2B0528E700E42968 /* Build configuration list for PBXNativeTarget "c3_window_cairo_quartz_demo" */;
- buildPhases = (
- 2A5417072B0528E500E42968 /* Sources */,
- 2A5417082B0528E500E42968 /* Frameworks */,
- 2A5417092B0528E500E42968 /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = c3_window_cairo_quartz_demo;
- productName = c3_window_cairo_quartz_demo;
- productReference = 2A54170B2B0528E500E42968 /* c3_window_cairo_quartz_demo.app */;
- productType = "com.apple.product-type.application";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- 2A5417032B0528E500E42968 /* Project object */ = {
- isa = PBXProject;
- attributes = {
- BuildIndependentTargetsInParallel = 1;
- LastSwiftUpdateCheck = 1500;
- LastUpgradeCheck = 1500;
- TargetAttributes = {
- 2A54170A2B0528E500E42968 = {
- CreatedOnToolsVersion = 15.0.1;
- };
- };
- };
- buildConfigurationList = 2A5417062B0528E500E42968 /* Build configuration list for PBXProject "demo" */;
- compatibilityVersion = "Xcode 14.0";
- developmentRegion = en;
- hasScannedForEncodings = 0;
- knownRegions = (
- en,
- Base,
- );
- mainGroup = 2A5417022B0528E500E42968;
- productRefGroup = 2A54170C2B0528E500E42968 /* Products */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- 2A54170A2B0528E500E42968 /* c3_window_cairo_quartz_demo */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
- 2A5417092B0528E500E42968 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
- 2A5417072B0528E500E42968 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 2A54171E2B052C0300E42968 /* c3_window_cairo_quartz_demo.c in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin XCBuildConfiguration section */
- 2A5417182B0528E700E42968 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_ENABLE_OBJC_WEAK = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- COPY_PHASE_STRIP = NO;
- DEBUG_INFORMATION_FORMAT = dwarf;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- ENABLE_TESTABILITY = YES;
- ENABLE_USER_SCRIPT_SANDBOXING = YES;
- GCC_C_LANGUAGE_STANDARD = gnu17;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
- MTL_FAST_MATH = YES;
- ONLY_ACTIVE_ARCH = YES;
- SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
- SWIFT_OPTIMIZATION_LEVEL = "-Onone";
- };
- name = Debug;
- };
- 2A5417192B0528E700E42968 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_ENABLE_OBJC_WEAK = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- COPY_PHASE_STRIP = NO;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- ENABLE_NS_ASSERTIONS = NO;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- ENABLE_USER_SCRIPT_SANDBOXING = YES;
- GCC_C_LANGUAGE_STANDARD = gnu17;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MTL_ENABLE_DEBUG_INFO = NO;
- MTL_FAST_MATH = YES;
- SWIFT_COMPILATION_MODE = wholemodule;
- };
- name = Release;
- };
- 2A54171B2B0528E700E42968 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- CODE_SIGN_ENTITLEMENTS = c3_window_cairo_quartz_demo.entitlements;
- CODE_SIGN_IDENTITY = "Apple Development";
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
- DEVELOPMENT_ASSET_PATHS = "\"Preview Content\"";
- DEVELOPMENT_TEAM = W4AD54MQ5Q;
- ENABLE_HARDENED_RUNTIME = YES;
- ENABLE_PREVIEWS = YES;
- GENERATE_INFOPLIST_FILE = YES;
- "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
- "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
- "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
- "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
- "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
- "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
- "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
- "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
- INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
- INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
- IPHONEOS_DEPLOYMENT_TARGET = 17.0;
- LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
- "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
- MACOSX_DEPLOYMENT_TARGET = 14.0;
- MARKETING_VERSION = 1.0;
- OTHER_CFLAGS = (
- "-I/opt/homebrew/include",
- "-I../../../../..",
- "-I../../../../../libffi/include",
- );
- OTHER_LDFLAGS = "-L/opt/homebrew/lib";
- PRODUCT_BUNDLE_IDENTIFIER = "kmx.io.c3-window-cairo-quartz-demo";
- PRODUCT_NAME = "$(TARGET_NAME)";
- PROVISIONING_PROFILE_SPECIFIER = "";
- SDKROOT = auto;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- };
- name = Debug;
- };
- 2A54171C2B0528E700E42968 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- CODE_SIGN_ENTITLEMENTS = c3_window_cairo_quartz_demo.entitlements;
- CODE_SIGN_IDENTITY = "Apple Development";
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
- DEVELOPMENT_ASSET_PATHS = "\"Preview Content\"";
- DEVELOPMENT_TEAM = W4AD54MQ5Q;
- ENABLE_HARDENED_RUNTIME = YES;
- ENABLE_PREVIEWS = YES;
- GENERATE_INFOPLIST_FILE = YES;
- "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
- "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
- "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
- "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
- "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
- "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
- "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
- "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
- INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
- INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
- IPHONEOS_DEPLOYMENT_TARGET = 17.0;
- LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
- "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
- MACOSX_DEPLOYMENT_TARGET = 14.0;
- MARKETING_VERSION = 1.0;
- OTHER_CFLAGS = (
- "-I/opt/homebrew/include",
- "-I../../../../..",
- "-I../../../../../libffi/include",
- );
- OTHER_LDFLAGS = "-L/opt/homebrew/lib";
- PRODUCT_BUNDLE_IDENTIFIER = "kmx.io.c3-window-cairo-quartz-demo";
- PRODUCT_NAME = "$(TARGET_NAME)";
- PROVISIONING_PROFILE_SPECIFIER = "";
- SDKROOT = auto;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- };
- name = Release;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 2A5417062B0528E500E42968 /* Build configuration list for PBXProject "demo" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 2A5417182B0528E700E42968 /* Debug */,
- 2A5417192B0528E700E42968 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 2A54171A2B0528E700E42968 /* Build configuration list for PBXNativeTarget "c3_window_cairo_quartz_demo" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 2A54171B2B0528E700E42968 /* Debug */,
- 2A54171C2B0528E700E42968 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
-/* End XCConfigurationList section */
- };
- rootObject = 2A5417032B0528E500E42968 /* Project object */;
-}
diff --git a/libkc3_window/cairo/quartz/demo/demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/libkc3_window/cairo/quartz/demo/demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
deleted file mode 100644
index 919434a..0000000
--- a/libkc3_window/cairo/quartz/demo/demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Workspace
- version = "1.0">
- <FileRef
- location = "self:">
- </FileRef>
-</Workspace>
diff --git a/libkc3_window/cairo/quartz/demo/demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/libkc3_window/cairo/quartz/demo/demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
deleted file mode 100644
index 18d9810..0000000
--- a/libkc3_window/cairo/quartz/demo/demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>IDEDidComputeMac32BitWarning</key>
- <true/>
-</dict>
-</plist>
diff --git a/libkc3_window/cairo/quartz/demo/demo.xcodeproj/xcuserdata/thodg.xcuserdatad/xcschemes/xcschememanagement.plist b/libkc3_window/cairo/quartz/demo/demo.xcodeproj/xcuserdata/thodg.xcuserdatad/xcschemes/xcschememanagement.plist
deleted file mode 100644
index f4a6f10..0000000
--- a/libkc3_window/cairo/quartz/demo/demo.xcodeproj/xcuserdata/thodg.xcuserdatad/xcschemes/xcschememanagement.plist
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>SchemeUserState</key>
- <dict>
- <key>c3_window_cairo_quartz_demo.xcscheme_^#shared#^_</key>
- <dict>
- <key>orderHint</key>
- <integer>0</integer>
- </dict>
- </dict>
-</dict>
-</plist>
diff --git a/libkc3_window/cairo/quartz/demo/sources.mk b/libkc3_window/cairo/quartz/demo/sources.mk
deleted file mode 100644
index 27c1b5e..0000000
--- a/libkc3_window/cairo/quartz/demo/sources.mk
+++ /dev/null
@@ -1,7 +0,0 @@
-# sources.mk generated by update_sources
-HEADERS = \
- "" \
-
-SOURCES = \
- "window_cairo_quartz_demo.c" \
-
diff --git a/libkc3_window/cairo/quartz/demo/sources.sh b/libkc3_window/cairo/quartz/demo/sources.sh
deleted file mode 100644
index 26d1842..0000000
--- a/libkc3_window/cairo/quartz/demo/sources.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-# sources.sh generated by update_sources
-HEADERS=' '
-SOURCES='window_cairo_quartz_demo.c '
diff --git a/libkc3_window/cairo/quartz/demo/update_sources b/libkc3_window/cairo/quartz/demo/update_sources
deleted file mode 100755
index 98e6491..0000000
--- a/libkc3_window/cairo/quartz/demo/update_sources
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-. ../../../../config.subr
-
-echo "$PWD/update_sources"
-
-echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
-echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
-
-#HEADERS="$(ls *.h | grep -v '^config.h$')"
-HEADERS=
-sources HEADERS "$HEADERS"
-
-SOURCES="$(ls *.c)"
-sources SOURCES "$SOURCES"
-
-update_sources_mk
-update_sources_sh
diff --git a/libkc3_window/cairo/quartz/demo/window_cairo_quartz_demo.c b/libkc3_window/cairo/quartz/demo/window_cairo_quartz_demo.c
deleted file mode 100644
index 0008b37..0000000
--- a/libkc3_window/cairo/quartz/demo/window_cairo_quartz_demo.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <stdio.h>
-#include <stdlib.h>
-#include <cairo/cairo.h>
-#include <libkc3/kc3.h>
-#include "../../../window.h"
-#include "../../demo/window_cairo_demo.h"
-#include "../window_cairo_quartz.h"
-
-int main (int argc, char **argv)
-{
- sw r = 0;
- s_window_cairo window;
- if (! c3_init(NULL, argc, argv))
- return 1;
- c3_window_cairo_init();
- window_cairo_init(&window, 0, 0, 800, 600,
- "C3.Window.Cairo.Quartz demo",
- WINDOW_CAIRO_DEMO_SEQUENCE_COUNT);
- window.button = window_cairo_demo_button;
- window.key = window_cairo_demo_key;
- window.load = window_cairo_demo_load;
- window.render = window_cairo_demo_render;
- window.resize = window_cairo_demo_resize;
- window.unload = window_cairo_demo_unload;
- if (! window_cairo_quartz_run(&window))
- r = g_c3_exit_code;
- window_cairo_clean(&window);
- c3_window_cairo_clean();
- c3_clean(NULL);
- return r;
-}
diff --git a/libkc3_window/cairo/quartz/quartz_to_xkbcommon.c b/libkc3_window/cairo/quartz/quartz_to_xkbcommon.c
deleted file mode 100644
index b41f8f9..0000000
--- a/libkc3_window/cairo/quartz/quartz_to_xkbcommon.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/types.h>
-#include <xkbcommon/xkbcommon.h>
-
-u32 quartz_to_xkbcommon (u16 quartz_key)
-{
- switch (quartz_key) {
- case 27: return XKB_KEY_Escape;
- case 63236: return XKB_KEY_F1;
- case 63237: return XKB_KEY_F2;
- case 63238: return XKB_KEY_F3;
- case 63239: return XKB_KEY_F4;
- case 63240: return XKB_KEY_F5;
- case 63241: return XKB_KEY_F6;
- case 63242: return XKB_KEY_F7;
- case 63243: return XKB_KEY_F8;
- case 63244: return XKB_KEY_F9;
- case 63245: return XKB_KEY_F10;
- case 63246: return XKB_KEY_F11;
- case 63247: return XKB_KEY_F12;
- case 96: return XKB_KEY_grave;
- case 49: return XKB_KEY_1;
- case 50: return XKB_KEY_2;
- case 51: return XKB_KEY_3;
- case 52: return XKB_KEY_4;
- case 53: return XKB_KEY_5;
- case 54: return XKB_KEY_6;
- case 55: return XKB_KEY_7;
- case 56: return XKB_KEY_8;
- case 57: return XKB_KEY_9;
- case 48: return XKB_KEY_0;
- case 45: return XKB_KEY_minus;
- case 61: return XKB_KEY_equal;
- case 127: return XKB_KEY_BackSpace;
- case 9: return XKB_KEY_Tab;
- case 97: return XKB_KEY_a;
- case 98: return XKB_KEY_b;
- case 99: return XKB_KEY_c;
- case 100: return XKB_KEY_d;
- case 101: return XKB_KEY_e;
- case 102: return XKB_KEY_f;
- case 103: return XKB_KEY_g;
- case 104: return XKB_KEY_h;
- case 105: return XKB_KEY_i;
- case 106: return XKB_KEY_j;
- case 107: return XKB_KEY_k;
- case 108: return XKB_KEY_l;
- case 109: return XKB_KEY_m;
- case 110: return XKB_KEY_n;
- case 111: return XKB_KEY_o;
- case 112: return XKB_KEY_p;
- case 113: return XKB_KEY_q;
- case 114: return XKB_KEY_r;
- case 115: return XKB_KEY_s;
- case 116: return XKB_KEY_t;
- case 117: return XKB_KEY_u;
- case 118: return XKB_KEY_v;
- case 119: return XKB_KEY_w;
- case 120: return XKB_KEY_x;
- case 121: return XKB_KEY_y;
- case 122: return XKB_KEY_z;
- case 91: return XKB_KEY_bracketleft;
- case 93: return XKB_KEY_bracketright;
- case 92: return XKB_KEY_backslash;
- case 59: return XKB_KEY_semicolon;
- case 39: return XKB_KEY_apostrophe;
- case 13: return XKB_KEY_Return;
- case 44: return XKB_KEY_comma;
- case 46: return XKB_KEY_period;
- case 47: return XKB_KEY_slash;
- case 63232: return XKB_KEY_Up;
- case 63233: return XKB_KEY_Down;
- case 63234: return XKB_KEY_Left;
- case 63235: return XKB_KEY_Right;
- default: break;
- }
- return XKB_KEY_NoSymbol;
-}
diff --git a/libkc3_window/cairo/quartz/quartz_to_xkbcommon.h b/libkc3_window/cairo/quartz/quartz_to_xkbcommon.h
deleted file mode 100644
index b1283da..0000000
--- a/libkc3_window/cairo/quartz/quartz_to_xkbcommon.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_QUARTZ_QUARTZ_TO_XKBCOMMON_H
-#define LIBKC3_WINDOW_CAIRO_QUARTZ_QUARTZ_TO_XKBCOMMON_H
-
-#include <libkc3/types.h>
-
-u32 quartz_to_xkbcommon (u16 quartz_key);
-
-#endif /* LIBKC3_WINDOW_CAIRO_QUARTZ_QUARTZ_TO_XKBCOMMON_H */
diff --git a/libkc3_window/cairo/quartz/sources.mk b/libkc3_window/cairo/quartz/sources.mk
deleted file mode 100644
index b1bdd8a..0000000
--- a/libkc3_window/cairo/quartz/sources.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-# sources.mk generated by update_sources
-HEADERS = \
- "quartz_to_xkbcommon.h" \
- "window_cairo_quartz.h" \
- "window_cairo_quartz_app_delegate.h" \
- "window_cairo_quartz_view.h" \
- "window_cairo_quartz_view_controller.h" \
- "xkbquartz.h" \
-
-SOURCES = \
- "quartz_to_xkbcommon.c" \
-
-OBJC_SOURCES = \
- "window_cairo_quartz.m" \
- "window_cairo_quartz_app_delegate.m" \
- "window_cairo_quartz_view.m" \
- "window_cairo_quartz_view_controller.m" \
-
diff --git a/libkc3_window/cairo/quartz/sources.sh b/libkc3_window/cairo/quartz/sources.sh
deleted file mode 100644
index 03cc583..0000000
--- a/libkc3_window/cairo/quartz/sources.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-# sources.sh generated by update_sources
-HEADERS='quartz_to_xkbcommon.h window_cairo_quartz.h window_cairo_quartz_app_delegate.h window_cairo_quartz_view.h window_cairo_quartz_view_controller.h xkbquartz.h '
-SOURCES='quartz_to_xkbcommon.c '
-OBJC_SOURCES='window_cairo_quartz.m window_cairo_quartz_app_delegate.m window_cairo_quartz_view.m window_cairo_quartz_view_controller.m '
diff --git a/libkc3_window/cairo/quartz/update_sources b/libkc3_window/cairo/quartz/update_sources
deleted file mode 100755
index e570876..0000000
--- a/libkc3_window/cairo/quartz/update_sources
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-. ../../../config.subr
-
-echo "$PWD/update_sources"
-
-echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
-echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
-
-HEADERS="$(ls *.h | grep -v '^config.h$')"
-sources HEADERS "$HEADERS"
-
-SOURCES="$(ls *.c)"
-sources SOURCES "$SOURCES"
-
-OBJC_SOURCES="$(ls *.m)"
-sources OBJC_SOURCES "$OBJC_SOURCES"
-
-update_sources_mk
-update_sources_sh
-
-( cd demo && ./update_sources; )
diff --git a/libkc3_window/cairo/quartz/window_cairo_quartz.h b/libkc3_window/cairo/quartz/window_cairo_quartz.h
deleted file mode 100644
index 289cd1f..0000000
--- a/libkc3_window/cairo/quartz/window_cairo_quartz.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_QUARTZ_H
-#define LIBKC3_WINDOW_CAIRO_QUARTZ_H
-
-#include <libkc3/types.h>
-#include "../types.h"
-#include "../window_cairo.h"
-
-bool window_cairo_quartz_run (s_window_cairo *window);
-
-#endif /* LIBKC3_WINDOW_CAIRO_XCB_H */
diff --git a/libkc3_window/cairo/quartz/window_cairo_quartz.m b/libkc3_window/cairo/quartz/window_cairo_quartz.m
deleted file mode 100644
index 04a9dc0..0000000
--- a/libkc3_window/cairo/quartz/window_cairo_quartz.m
+++ /dev/null
@@ -1,31 +0,0 @@
-/* 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.
- */
-#import <Cocoa/Cocoa.h>
-#import "window_cairo_quartz.h"
-#import "window_cairo_quartz_app_delegate.h"
-
-bool window_cairo_quartz_run (s_window_cairo *window)
-{
- @autoreleasepool {
- NSApplication *app = [NSApplication sharedApplication];
- WindowCairoQuartzAppDelegate *app_delegate = [[WindowCairoQuartzAppDelegate alloc] initWithWindowCairo:window];
- [app setDelegate:app_delegate];
- [app run];
- }
- return true;
-}
-
-bool window_cairo_run (s_window_cairo *window)
-{
- return window_cairo_quartz_run(window);
-}
diff --git a/libkc3_window/cairo/quartz/window_cairo_quartz_app_delegate.h b/libkc3_window/cairo/quartz/window_cairo_quartz_app_delegate.h
deleted file mode 100644
index 005d9ec..0000000
--- a/libkc3_window/cairo/quartz/window_cairo_quartz_app_delegate.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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.
- */
-#import <Cocoa/Cocoa.h>
-#import "../window_cairo.h"
-#import "window_cairo_quartz_view.h"
-
-@interface WindowCairoQuartzAppDelegate : NSObject <NSApplicationDelegate,
- NSWindowDelegate>
-
-@property (strong, nonatomic) NSView *view;
-@property (strong, nonatomic) NSWindow *window;
-@property (nonatomic, assign) s_window_cairo *window_cairo;
-
-- (instancetype) initWithWindowCairo:(s_window_cairo *) window_cairo;
-
-@end
diff --git a/libkc3_window/cairo/quartz/window_cairo_quartz_app_delegate.m b/libkc3_window/cairo/quartz/window_cairo_quartz_app_delegate.m
deleted file mode 100644
index 4b7d923..0000000
--- a/libkc3_window/cairo/quartz/window_cairo_quartz_app_delegate.m
+++ /dev/null
@@ -1,85 +0,0 @@
-/* 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.
- */
-#import "window_cairo_quartz_app_delegate.h"
-#import "window_cairo_quartz_view.h"
-#import "window_cairo_quartz_view_controller.h"
-
-@implementation WindowCairoQuartzAppDelegate
-
-- (instancetype) initWithWindowCairo:(s_window_cairo *)window_cairo {
- self = [super init];
- if (self) {
- self.window_cairo = window_cairo;
- }
- return self;
-}
-
-- (void)applicationDidFinishLaunching:(NSNotification *)notification {
- NSRect frame = NSMakeRect(self.window_cairo->x, self.window_cairo->y,
- self.window_cairo->w, self.window_cairo->h);
- self.window = [[NSWindow alloc]
- initWithContentRect:frame
- styleMask:(NSWindowStyleMaskTitled |
- NSWindowStyleMaskClosable |
- NSWindowStyleMaskResizable)
- backing:NSBackingStoreBuffered
- defer:NO];
- [self.window setDelegate:self];
- [self.window makeKeyAndOrderFront:nil];
- [self.window
- setTitle:[NSString
- stringWithUTF8String:self.window_cairo->title]];
-
- WindowCairoQuartzView *view =
- [[WindowCairoQuartzView alloc]
- initWithWindowCairo:self.window_cairo];
- WindowCairoQuartzViewController *view_controller =
- [[WindowCairoQuartzViewController alloc]
- initWithCairoView:view];
- self.view = view;
- [self.window setContentView:view_controller.view];
- [self.window setAcceptsMouseMovedEvents:YES];
- if (! self.window_cairo->load(self.window_cairo)) {
- [self.window close];
- [self.window release];
- [[NSApplication sharedApplication] stop:nil];
- exit(1);
- }
- [NSTimer scheduledTimerWithTimeInterval:0.01
- target:self
- selector:@selector(redrawWindow)
- userInfo:nil
- repeats:YES];
-}
-
-- (void)redrawWindow {
- [self.view setNeedsDisplay:YES];
-}
-
-- (void)windowDidResize:(NSNotification *)notification {
- printf("windowDidResize\n");
- NSWindow *window = (NSWindow *)notification.object;
- NSSize size = window.frame.size;
- [self.view setFrameSize:size];
- if (! self.window_cairo->resize(self.window_cairo, (uw) size.width,
- size.height))
- [NSApp stop:nil];
- self.window_cairo->w = size.width;
- self.window_cairo->h = size.height;
-}
-
-- (void)windowWillClose:(NSNotification *)notification {
- [NSApp stop:nil];
-}
-
-@end
diff --git a/libkc3_window/cairo/quartz/window_cairo_quartz_view.h b/libkc3_window/cairo/quartz/window_cairo_quartz_view.h
deleted file mode 100644
index 6b7ceef..0000000
--- a/libkc3_window/cairo/quartz/window_cairo_quartz_view.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_QUARTZ_VIEW_H
-#define LIBKC3_WINDOW_CAIRO_QUARTZ_VIEW_H
-
-#import <Cocoa/Cocoa.h>
-#import "../window_cairo.h"
-
-@interface WindowCairoQuartzView : NSView
-
-@property (nonatomic, assign) s_window_cairo *window_cairo;
-
-- (BOOL)acceptsFirstResponder;
-
-- (void) drawRect:(NSRect)dirtyRect;
-
-- (instancetype)initWithWindowCairo:(s_window_cairo *) window_cairo;
-
-- (void)keyDown:(NSEvent *)event;
-
-@end
-
-#endif /* LIBKC3_WINDOW_CAIRO_QUARTZ_VIEW_H */
diff --git a/libkc3_window/cairo/quartz/window_cairo_quartz_view.m b/libkc3_window/cairo/quartz/window_cairo_quartz_view.m
deleted file mode 100644
index 97d20ba..0000000
--- a/libkc3_window/cairo/quartz/window_cairo_quartz_view.m
+++ /dev/null
@@ -1,96 +0,0 @@
-/* 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.
- */
-#import <Foundation/Foundation.h>
-#import <cairo/cairo-quartz.h>
-#import <xkbcommon/xkbcommon.h>
-#import "quartz_to_xkbcommon.h"
-#import "window_cairo_quartz_view.h"
-
-@implementation WindowCairoQuartzView
-
-- (instancetype) initWithWindowCairo:(s_window_cairo *) window_cairo {
- NSRect frame = NSMakeRect(window_cairo->x, window_cairo->y, window_cairo->w, window_cairo->h);
- self = [super initWithFrame:frame];
- if (self) {
- self.window_cairo = window_cairo;
- }
- return self;
-}
-
-- (BOOL)acceptsFirstResponder {
- return YES;
-}
-
-- (void) drawRect:(NSRect)dirtyRect {
- [super drawRect:dirtyRect];
- struct CGContext *cg_context = [[NSGraphicsContext currentContext]
- CGContext];
- CGContextTranslateCTM(cg_context, 0.0, self.bounds.size.height);
- CGContextScaleCTM(cg_context, 1.0, -1.0);
- cairo_surface_t *surface =
- cairo_quartz_surface_create_for_cg_context(cg_context,
- self.bounds.size.width,
- self.bounds.size.height);
- cairo_t *cr = cairo_create(surface);
- self.window_cairo->cr = cr;
- if (! self.window_cairo->render(self.window_cairo)) {
- [self.window close];
- [self.window release];
- [[NSApplication sharedApplication] stop:nil];
- }
- cairo_surface_flush(surface);
- cairo_destroy(cr);
- cairo_surface_destroy(surface);
-}
-
-- (void)keyDown:(NSEvent *)event {
- NSString *characters = [event characters];
- unichar character = [characters characterAtIndex:0];
- u32 keysym = quartz_to_xkbcommon(character);
- if (! self.window_cairo->key(self.window_cairo, keysym)) {
- [self.window close];
- [self.window release];
- [[NSApplication sharedApplication] stop:nil];
- }
-}
-
-- (void)mouseDown:(NSEvent *)event {
- NSPoint p = [event locationInWindow];
- if (! self.window_cairo->button(self.window_cairo, 0, p.x, p.y)) {
- [self.window close];
- [self.window release];
- [[NSApplication sharedApplication] stop:nil];
- }
-}
-
-- (void)mouseMoved:(NSEvent *)event {
- NSPoint p = [event locationInWindow];
- p.y = self.window_cairo->h - p.y;
- if (! self.window_cairo->motion(self.window_cairo, p.x, p.y)) {
- [self.window close];
- [self.window release];
- [[NSApplication sharedApplication] stop:nil];
- }
-}
-
-- (void)rightMouseDown:(NSEvent *)event {
- NSPoint p = [event locationInWindow];
- if (! self.window_cairo->button(self.window_cairo, 2, p.x, p.y)) {
- [self.window close];
- [self.window release];
- [[NSApplication sharedApplication] stop:nil];
- }
-}
-
-@end
-
diff --git a/libkc3_window/cairo/quartz/window_cairo_quartz_view_controller.h b/libkc3_window/cairo/quartz/window_cairo_quartz_view_controller.h
deleted file mode 100644
index 20b69db..0000000
--- a/libkc3_window/cairo/quartz/window_cairo_quartz_view_controller.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_QUARTZ_VIEW_CONTROLLER_H
-#define LIBKC3_WINDOW_CAIRO_QUARTZ_VIEW_CONTROLLER_H
-
-#import <Cocoa/Cocoa.h>
-#import "window_cairo_quartz_view.h"
-
-@interface WindowCairoQuartzViewController : NSViewController
-
-@property (strong) WindowCairoQuartzView *cairo_view;
-
-- (instancetype) initWithCairoView:(WindowCairoQuartzView *)cairo_view;
-
-@end
-
-#endif /* LIBKC3_WINDOW_CAIRO_QUARTZ_VIEW_CONTROLLER_H */
diff --git a/libkc3_window/cairo/quartz/window_cairo_quartz_view_controller.m b/libkc3_window/cairo/quartz/window_cairo_quartz_view_controller.m
deleted file mode 100644
index 26c8358..0000000
--- a/libkc3_window/cairo/quartz/window_cairo_quartz_view_controller.m
+++ /dev/null
@@ -1,36 +0,0 @@
-/* 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.
- */
-#import <Cocoa/Cocoa.h>
-#import "window_cairo_quartz_view_controller.h"
-
-@implementation WindowCairoQuartzViewController
-
-- (instancetype) initWithCairoView:(WindowCairoQuartzView *)cairo_view {
- self = [super init];
- if (self) {
- self.cairo_view = cairo_view;
- }
- return self;
-}
-
-- (void)viewDidLoad {
- [super viewDidLoad];
- [self.view addSubview:self.cairo_view];
-}
-
-- (void)viewDidAppear {
- [super viewDidAppear];
- [self.view.window makeFirstResponder:self.cairo_view];
-}
-
-@end
diff --git a/libkc3_window/cairo/quartz/xkbquartz.h b/libkc3_window/cairo/quartz/xkbquartz.h
deleted file mode 100644
index 9b2f1a6..0000000
--- a/libkc3_window/cairo/quartz/xkbquartz.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_QUARTZ_H
-#define LIBKC3_WINDOW_CAIRO_QUARTZ_H
-
-
-
-#endif /* LIBKC3_WINDOW_CAIRO_XCB_H */
diff --git a/libkc3_window/cairo/sources.mk b/libkc3_window/cairo/sources.mk
deleted file mode 100644
index cd231cc..0000000
--- a/libkc3_window/cairo/sources.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-# sources.mk generated by update_sources
-HEADERS = \
- "cairo_font.h" \
- "cairo_sprite.h" \
- "cairo_text.h" \
- "types.h" \
- "window_cairo.h" \
-
-SOURCES = \
- "cairo_font.c" \
- "cairo_sprite.c" \
- "cairo_text.c" \
- "window_cairo.c" \
-
diff --git a/libkc3_window/cairo/sources.sh b/libkc3_window/cairo/sources.sh
deleted file mode 100644
index 7fcb3b5..0000000
--- a/libkc3_window/cairo/sources.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-# sources.sh generated by update_sources
-HEADERS='cairo_font.h cairo_sprite.h cairo_text.h types.h window_cairo.h '
-SOURCES='cairo_font.c cairo_sprite.c cairo_text.c window_cairo.c '
diff --git a/libkc3_window/cairo/types.h b/libkc3_window/cairo/types.h
deleted file mode 100644
index 4bd73ac..0000000
--- a/libkc3_window/cairo/types.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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.
- */
-/** @file types.h
- * @brief Module C3.Window.Cairo
- *
- * Struct for all GUI window Cairo graphics operations.
- */
-#ifndef LIBKC3_WINDOW_CAIRO_TYPES_H
-#define LIBKC3_WINDOW_CAIRO_TYPES_H
-
-#include <cairo.h>
-#include <cairo-ft.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include <png.h>
-#include <libkc3/types.h>
-#include "../types.h"
-
-typedef struct cairo_font s_cairo_font;
-typedef struct cairo_sprite s_cairo_sprite;
-typedef struct rgb s_rgb;
-typedef struct rgba s_rgba;
-typedef struct window_cairo s_window_cairo;
-
-/* return false to break event loop */
-typedef bool (*f_window_cairo_button) (s_window_cairo *window,
- u8 button, sw x, sw y);
-
-/* return false to break event loop */
-typedef bool (*f_window_cairo_key) (s_window_cairo *window, uw keysym);
-
-/* return false to break event loop */
-typedef bool (*f_window_cairo_load) (s_window_cairo *window);
-
-/* return false to break event loop */
-typedef bool (*f_window_cairo_motion) (s_window_cairo *window, sw x,
- sw y);
-
-/* return false to break event loop */
-typedef bool (*f_window_cairo_render) (s_window_cairo *window);
-
-/* return false to break event loop */
-typedef bool (*f_window_cairo_resize) (s_window_cairo *window,
- uw w, uw h);
-
-typedef void (*f_window_cairo_unload) (s_window_cairo *window);
-
-struct cairo_font {
- cairo_font_face_t *cairo_font_face;
- FT_Face ft_face;
- s_str path;
- s_str real_path;
-};
-
-struct cairo_sprite {
- s_str path;
- s_str real_path;
- uw total_w;
- uw total_h;
- uw dim_x;
- uw dim_y;
- uw frame_count;
- uw w;
- uw h;
- //ILuint *il_image;
- cairo_surface_t **surface;
-};
-
-struct rgb {
- double r;
- double g;
- double b;
-};
-
-struct rgba {
- double r;
- double g;
- double b;
- double a;
-};
-
-/* Subtype of s_window. See libkc3/window/types.h */
-struct window_cairo {
- sw x;
- sw y;
- uw w;
- uw h;
- bool fullscreen;
- f_window_cairo_button button;
- f_window_cairo_key key;
- f_window_cairo_load load;
- f_window_cairo_motion motion;
- f_window_cairo_render render;
- cairo_t *cr;
- f_window_cairo_resize resize;
- s_sequence *seq;
- s_sequence *sequence;
- uw sequence_count;
- uw sequence_pos;
- s_tag tag; // TODO: move sequence to tag
- const char *title;
- f_window_cairo_unload unload;
-};
-
-#endif /* LIBKC3_WINDOW_CAIRO_TYPES_H */
diff --git a/libkc3_window/cairo/update_sources b/libkc3_window/cairo/update_sources
deleted file mode 100755
index 7b6ba22..0000000
--- a/libkc3_window/cairo/update_sources
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-. ../../config.subr
-
-echo "$PWD/update_sources"
-
-echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
-echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
-
-HEADERS="$(ls *.h | grep -v '^config.h$')"
-sources HEADERS "$HEADERS"
-
-SOURCES="$(ls *.c)"
-sources SOURCES "$SOURCES"
-
-update_sources_mk
-update_sources_sh
-
-( cd demo && ./update_sources; )
-( cd quartz && ./update_sources; )
-( cd win32 && ./update_sources; )
-( cd xcb && ./update_sources; )
diff --git a/libkc3_window/cairo/win32/Makefile b/libkc3_window/cairo/win32/Makefile
deleted file mode 100644
index 2d8037a..0000000
--- a/libkc3_window/cairo/win32/Makefile
+++ /dev/null
@@ -1,92 +0,0 @@
-## kc3
-## Copyright 2022-2024 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.
-
-CLEANFILES = *.a *.gcno *.la .libs *.lo *.o
-
-CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
-
-CLEANFILES += ${CLEANFILES_COV}
-
-DISTCLEANFILES = ${CLEANFILES} config.h config.mk
-
-build:
- ${MAKE} ${LIB}
- ${MAKE} -C demo build
-
-all:
- ${MAKE} build
- if ${HAVE_GCOV}; then ${MAKE} cov; fi
- ${MAKE} debug
- if ${HAVE_ASAN}; then ${MAKE} asan; fi
-
-asan:
- ${MAKE} ${LIB_ASAN}
- ${MAKE} -C demo asan
-
-clean:
- rm -rf ${CLEANFILES}
- ${MAKE} -C demo clean
-
-clean_cov:
- rm -rf ${CLEANFILES_COV}
- ${MAKE} -C demo clean_cov
-
-cov:
- ${MAKE} ${LIB_COV}
- ${MAKE} -C demo cov
-
-debug:
- ${MAKE} ${LIB_DEBUG}
- ${MAKE} -C demo debug
-
-demo: build
- ${MAKE} -C demo demo
-
-demo_asan: asan
- ${MAKE} -C demo demo_asan
-
-demo_cov: cov
- ${MAKE} -C demo demo_cov
-
-demo_debug: debug
- ${MAKE} -C demo demo_debug
-
-distclean:
- rm -rf ${DISTCLEANFILES}
- ${MAKE} -C demo distclean
-
-gdb_demo: debug
- ${MAKE} -C demo gdb_demo
-
-test: build
- ${MAKE} -C demo test
-
-update_sources:
- ./update_sources
-
-.PHONY: \
- all \
- asan \
- build \
- clean \
- cov \
- debug \
- demo \
- distclean \
- gdb_demo \
- gen \
- install \
- test \
- update_sources
-
-include config.mk
-include sources.mk
diff --git a/libkc3_window/cairo/win32/configure b/libkc3_window/cairo/win32/configure
deleted file mode 100644
index 885d1d4..0000000
--- a/libkc3_window/cairo/win32/configure
+++ /dev/null
@@ -1,149 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-set -e
-
-export SRC_TOP="$(dirname "$PWD")"
-
-. ../../../../config.subr
-
-LIB=libkc3_window_cairo_win32.la
-LIB_ASAN=libkc3_window_cairo_win32_asan.la
-LIB_COV=libkc3_window_cairo_win32_cov.la
-LIB_DEBUG=libkc3_window_cairo_win32_debug.la
-
-echo "LIB = $LIB" >> ${CONFIG_MK}
-echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
-echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
-echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
-
-#LIBKC3=../../../libkc3.la
-#LIBKC3_ASAN=../../../libkc3_asan.la
-#LIBKC3_COV=../../../libkc3_cov.la
-#LIBKC3_DEBUG=../../../libkc3_debug.la
-
-. ./sources.sh
-
-OBJECTS="$(c2ext .main.lo "$SOURCES")"
-echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
-OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
-OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
-OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
-
-# Common config for all targets
-CPPFLAGS="-I../../../../libffi/include -I../../../.. $CPPFLAGS"
-CFLAGS="$CFLAGS -W -Wall -Werror -std=c99 -pedantic"
-LDFLAGS="--shared $LDFLAGS"
-LIBS="$LIBS -rpath ${PREFIX}/lib"
-config_asan
-config_gnu
-config_i386
-pkg_config xkbcommon
-pkg_config cairo
-pkg_config cairo-win32
-pkg_config libbsd-overlay
-pkg_config libmd
-config_define PREFIX "\"${PREFIX}\""
-update_config_h
-LIBS="$LIBS -lxkbcommon"
-
-# Address Sanitizer config
-CFLAGS_ASAN="$CFLAGS -O1 -fsanitize=address -fno-omit-frame-pointer -g"
-LDFLAGS_ASAN="$LDFLAGS"
-LIBS_LOCAL_ASAN="../libkc3_window_cairo_asan.la"
-LIBS_ASAN="$LIBS_LOCAL_ASAN $LIBS"
-
-# Coverage config
-CFLAGS_COV="$CFLAGS -ftest-coverage -fprofile-arcs -fprofile-generate"
-LDFLAGS_COV="$LDFLAGS --coverage"
-LIBS_LOCAL_COV="../libkc3_window_cairo_cov.la"
-LIBS_COV="$LIBS_LOCAL_COV $LIBS"
-
-# Debug config
-CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
-LDFLAGS_DEBUG="$LDFLAGS"
-LIBS_LOCAL_DEBUG="../libkc3_window_cairo_debug.la"
-LIBS_DEBUG="$LIBS_LOCAL_DEBUG $LIBS"
-
-# Main config
-DEFAULT_CFLAGS="-O2 -pipe"
-if [ "x$ENV_CFLAGS" = "x" ]; then
- CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
-fi
-CFLAGS="$CFLAGS -DNDEBUG"
-LIBS_LOCAL="../libkc3_window_cairo.la"
-LIBS="$LIBS_LOCAL $LIBS"
-
-echo "LIB = $LIB" >> ${CONFIG_MK}
-echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
-echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
-echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
-echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
-echo "LIBS = $LIBS" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
-echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
-echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
-echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
-echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
-echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
-
-echo >> ${CONFIG_MK}
-echo "$LIB: $LIBS_LOCAL $OBJECTS" >> ${CONFIG_MK}
-echo " ${LIBTOOL} --tag=CC --mode=link \${CC} -shared \${LDFLAGS} ${OBJECTS} \${LIBS} -rpath ${LIBDIR} -o ${LIB}" >> ${CONFIG_MK}
-
-echo >> ${CONFIG_MK}
-echo "$LIB_ASAN: $LIBS_LOCAL_ASAN $OBJECTS_ASAN" >> ${CONFIG_MK}
-echo " ${LIBTOOL} --tag=CC --mode=link \${CC} -shared \${LDFLAGS_ASAN} ${OBJECTS_ASAN} \${LIBS_ASAN} -rpath ${LIBDIR} -o ${LIB_ASAN}" >> ${CONFIG_MK}
-
-echo >> ${CONFIG_MK}
-echo "$LIB_COV: $LIBS_LOCAL_COV $OBJECTS_COV" >> ${CONFIG_MK}
-echo " ${LIBTOOL} --tag=CC --mode=link \${CC} -shared \${LDFLAGS_COV} ${OBJECTS_COV} \${LIBS_COV} -rpath ${LIBDIR} -o ${LIB_COV}" >> ${CONFIG_MK}
-
-echo >> ${CONFIG_MK}
-echo "$LIB_DEBUG: $LIBS_LOCAL_DEBUG $OBJECTS_DEBUG" >> ${CONFIG_MK}
-echo " ${LIBTOOL} --tag=CC --mode=link \${CC} -shared \${LDFLAGS_DEBUG} ${OBJECTS_DEBUG} \${LIBS_DEBUG} -rpath ${LIBDIR} -o ${LIB_DEBUG}" >> ${CONFIG_MK}
-
-for SRC in $SOURCES; do
- echo >> ${CONFIG_MK}
- SRC_LO="$(c2ext .main.lo "$SRC")"
- c_ext_rule .main.lo "$SRC" >> ${CONFIG_MK}
- echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS} -c $SRC -o $SRC_LO" >> ${CONFIG_MK}
-
- echo >> ${CONFIG_MK}
- SRC_ASAN_LO="$(c2ext .asan.lo "$SRC")"
- c_ext_rule .asan.lo "$SRC" >> ${CONFIG_MK}
- echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_ASAN} -c $SRC -o $SRC_ASAN_LO" >> ${CONFIG_MK}
-
- echo >> ${CONFIG_MK}
- SRC_COV_LO="$(c2ext .cov.lo "$SRC")"
- c_ext_rule .cov.lo "$SRC" >> ${CONFIG_MK}
- echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_COV} -c $SRC -o $SRC_COV_LO" >> ${CONFIG_MK}
-
- echo >> ${CONFIG_MK}
- SRC_DEBUG_LO="$(c2ext .debug.lo "$SRC")"
- c_ext_rule .debug.lo "$SRC" >> ${CONFIG_MK}
- echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_DEBUG} -c $SRC -o $SRC_DEBUG_LO" >> ${CONFIG_MK}
-done
-
-update_config_mk
-env_reset
-( cd demo && ./configure; )
diff --git a/libkc3_window/cairo/win32/demo/Makefile b/libkc3_window/cairo/win32/demo/Makefile
deleted file mode 100644
index 89a2497..0000000
--- a/libkc3_window/cairo/win32/demo/Makefile
+++ /dev/null
@@ -1,78 +0,0 @@
-## kc3
-## Copyright 2022-2024 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 config.mk
-include sources.mk
-
-CLEANFILES = *.a ${PROG} ${PROG_ASAN} ${PROG_COV} ${PROG_DEBUG} *.css \
- *.gcno *.html *.o .libs *.lo
-
-CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
-CLEANFILES += ${CLEANFILES_COV}
-
-DISTCLEANFILES = ${CLEANFILES} config.mk
-
-build: ${PROG}
-
-all:
- ${MAKE} build
- if ${HAVE_GCOV}; then ${MAKE} cov; fi
- ${MAKE} debug
- if ${HAVE_ASAN}; then ${MAKE} asan; fi
-
-asan: ${PROG_ASAN}
-
-clean:
- rm -rf ${CLEANFILES}
-
-clean_cov:
- rm -rf ${CLEANFILES_COV}
-
-cov: ${PROG_COV}
-
-debug: ${PROG_DEBUG}
-
-demo: ${PROG}
- time ./${PROG}
-
-demo_asan: ${PROG_ASAN}
- time ./${PROG_ASAN}
-
-demo_cov: ${PROG_COV}
- time ./${PROG_COV}
-
-demo_debug: ${PROG_DEBUG}
- time ./${PROG_DEBUG}
-
-distclean:
- rm -rf ${DISTCLEANFILES}
-
-gcovr:
- gcovr --gcov-executable ${GCOV} --html-details ${PROG}.html
-
-gdb_demo: debug
- if [ -f ${PROG_DEBUG}.core ]; then gdb .libs/${PROG_DEBUG} ${PROG_DEBUG}.core; else gdb .libs/${PROG_DEBUG}; fi
-
-install:
- install -m 755 -d ${prefix}/bin
- install -m 755 ${PROG} ${prefix}/bin/${PROG}
-
-.PHONY: \
- all \
- asan \
- clean \
- clean_cov \
- cov \
- debug \
- demo \
- distclean \
- gdb_demo
diff --git a/libkc3_window/cairo/win32/demo/configure b/libkc3_window/cairo/win32/demo/configure
deleted file mode 100644
index 11b1cb7..0000000
--- a/libkc3_window/cairo/win32/demo/configure
+++ /dev/null
@@ -1,144 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-set -e
-
-export SRC_TOP="$(dirname "$PWD")"
-
-. ../../../../../config.subr
-
-PROG=c3_window_cairo_win32_demo
-PROG_ASAN=c3_window_cairo_win32_demo_asan
-PROG_COV=c3_window_cairo_win32_demo_cov
-PROG_DEBUG=c3_window_cairo_win32_demo_debug
-
-echo "PROG = $PROG" >> ${CONFIG_MK}
-echo "PROG_ASAN = $PROG_ASAN" >> ${CONFIG_MK}
-echo "PROG_COV = $PROG_COV" >> ${CONFIG_MK}
-echo "PROG_DEBUG = $PROG_DEBUG" >> ${CONFIG_MK}
-
-. ./sources.sh
-
-OBJECTS="$(c2ext .main.lo "$SOURCES")"
-echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
-
-OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
-echo "OBJECTS_ASAN = $OBJECTS_ASAN" >> ${CONFIG_MK}
-
-if $HAVE_GCOV; then
- OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
- echo "OBJECTS_COV = $OBJECTS_COV" >> ${CONFIG_MK}
-fi
-
-OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
-echo "OBJECTS_DEBUG = $OBJECTS_DEBUG" >> ${CONFIG_MK}
-
-# Common config for all targets
-CFLAGS="$CFLAGS -W -Wall -Werror -std=c99 -pedantic"
-CPPFLAGS="-I../../../../../libffi/include -I../../../../.. $CPPFLAGS"
-config_asan
-config_gnu
-config_i386
-pkg_config libbsd-overlay
-pkg_config cairo
-pkg_config cairo-win32
-LIBS="$LIBS"
-
-# Asan config
-CFLAGS_ASAN="$CFLAGS -fsanitize=address -O1 -fno-omit-frame-pointer -g"
-LDFLAGS_ASAN="$LDFLAGS"
-LOCAL_LIBS_ASAN="../../demo/libkc3_window_cairo_demo_asan.la ../libkc3_window_cairo_win32_asan.la"
-LIBS_ASAN="$LOCAL_LIBS_ASAN $LIBS"
-
-# Coverage config
-CFLAGS_COV="$CFLAGS -ftest-coverage -fprofile-arcs -fprofile-generate"
-LDFLAGS_COV="$LDFLAGS --coverage"
-LOCAL_LIBS_COV="../../demo/libkc3_window_cairo_demo_cov.la ../libkc3_window_cairo_win32_cov.la"
-LIBS_COV="$LOCAL_LIBS_COV $LIBS"
-
-# Debug config
-CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
-LDFLAGS_DEBUG="$LDFLAGS"
-LOCAL_LIBS_DEBUG="../../demo/libkc3_window_cairo_demo_debug.la ../libkc3_window_cairo_win32_debug.la"
-LIBS_DEBUG="$LOCAL_LIBS_DEBUG $LIBS"
-
-# Main config
-DEFAULT_CFLAGS="-O2 -pipe"
-if [ "x$ENV_CFLAGS" = "x" ]; then
- CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
-fi
-CFLAGS="$CFLAGS -DNDEBUG"
-LOCAL_LIBS="../../demo/libkc3_window_cairo_demo.la ../libkc3_window_cairo_win32.la"
-LIBS="$LOCAL_LIBS $LIBS"
-
-echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
-echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
-echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
-echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
-echo "LIBS = $LIBS" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
-echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
-echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
-
-echo >> ${CONFIG_MK}
-echo "$PROG: $LOCAL_LIBS $OBJECTS" >> ${CONFIG_MK}
-echo " ${LIBTOOL} --tag=CC --mode=link \${CC} \${CFLAGS} \${LDFLAGS} ${OBJECTS} ${LIBS} -o $PROG" >> ${CONFIG_MK}
-
-echo >> ${CONFIG_MK}
-echo "$PROG_ASAN: $LOCAL_LIBS_ASAN $OBJECTS_ASAN" >> ${CONFIG_MK}
-echo " ${LIBTOOL} --tag=CC --mode=link \${CC} \${CFLAGS_ASAN} \${LDFLAGS_ASAN} ${OBJECTS_ASAN} ${LIBS_ASAN} -o $PROG_ASAN" >> ${CONFIG_MK}
-
-if $HAVE_GCOV; then
- echo >> ${CONFIG_MK}
- echo "$PROG_COV: $LOCAL_LIBS_COV $OBJECTS_COV" >> ${CONFIG_MK}
- echo " ${LIBTOOL} --tag=CC --mode=link \${CC} \${CFLAGS_COV} \${LDFLAGS_COV} ${OBJECTS_COV} ${LIBS_COV} -o $PROG_COV" >> ${CONFIG_MK}
-fi
-
-echo >> ${CONFIG_MK}
-echo "$PROG_DEBUG: $LOCAL_LIBS_DEBUG $OBJECTS_DEBUG" >> ${CONFIG_MK}
-echo " ${LIBTOOL} --tag=CC --mode=link \${CC} \${CFLAGS_DEBUG} \${LDFLAGS_DEBUG} ${OBJECTS_DEBUG} ${LIBS_DEBUG} -o $PROG_DEBUG" >> ${CONFIG_MK}
-
-for SRC in $SOURCES; do
- echo >> ${CONFIG_MK}
- SRC_LO="$(c2ext .main.lo "$SRC")"
- c_ext_rule .main.lo "$SRC" >> ${CONFIG_MK}
- echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS} -c $SRC -o $SRC_LO" >> ${CONFIG_MK}
-
- echo >> ${CONFIG_MK}
- SRC_ASAN_LO="$(c2ext .asan.lo "$SRC")"
- c_ext_rule .asan.lo "$SRC" >> ${CONFIG_MK}
- echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_ASAN} -c $SRC -o $SRC_ASAN_LO" >> ${CONFIG_MK}
-
- if $HAVE_GCOV; then
- echo >> ${CONFIG_MK}
- SRC_COV_LO="$(c2ext .cov.lo "$SRC")"
- c_ext_rule .cov.lo "$SRC" >> ${CONFIG_MK}
- echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_COV} -c $SRC -o $SRC_COV_LO" >> ${CONFIG_MK}
- fi
-
- echo >> ${CONFIG_MK}
- SRC_DEBUG_LO="$(c2ext .debug.lo "$SRC")"
- c_ext_rule .debug.lo "$SRC" >> ${CONFIG_MK}
- echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_DEBUG} -c $SRC -o $SRC_DEBUG_LO" >> ${CONFIG_MK}
-done
-
-update_config_mk
diff --git a/libkc3_window/cairo/win32/demo/sources.mk b/libkc3_window/cairo/win32/demo/sources.mk
deleted file mode 100644
index 1dc7825..0000000
--- a/libkc3_window/cairo/win32/demo/sources.mk
+++ /dev/null
@@ -1,7 +0,0 @@
-# sources.mk generated by update_sources
-HEADERS = \
- "" \
-
-SOURCES = \
- "window_cairo_win32_demo.c" \
-
diff --git a/libkc3_window/cairo/win32/demo/sources.sh b/libkc3_window/cairo/win32/demo/sources.sh
deleted file mode 100644
index 9df3998..0000000
--- a/libkc3_window/cairo/win32/demo/sources.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-# sources.sh generated by update_sources
-HEADERS=' '
-SOURCES='window_cairo_win32_demo.c '
diff --git a/libkc3_window/cairo/win32/demo/update_sources b/libkc3_window/cairo/win32/demo/update_sources
deleted file mode 100755
index 98e6491..0000000
--- a/libkc3_window/cairo/win32/demo/update_sources
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-. ../../../../config.subr
-
-echo "$PWD/update_sources"
-
-echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
-echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
-
-#HEADERS="$(ls *.h | grep -v '^config.h$')"
-HEADERS=
-sources HEADERS "$HEADERS"
-
-SOURCES="$(ls *.c)"
-sources SOURCES "$SOURCES"
-
-update_sources_mk
-update_sources_sh
diff --git a/libkc3_window/cairo/win32/demo/window_cairo_win32_demo.c b/libkc3_window/cairo/win32/demo/window_cairo_win32_demo.c
deleted file mode 100644
index 0443ebd..0000000
--- a/libkc3_window/cairo/win32/demo/window_cairo_win32_demo.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <stdio.h>
-#include <stdlib.h>
-#include <cairo/cairo.h>
-#include <libkc3/kc3.h>
-#include "../../../window.h"
-#include "../../demo/window_cairo_demo.h"
-#include "../window_cairo_win32.h"
-
-int main (int argc, char **argv)
-{
- s_window_cairo window;
- if (! c3_init(NULL, argc, argv))
- return 1;
- c3_window_cairo_init();
- window_cairo_init(&window, 0, 0, 800, 600,
- "C3.Window.Cairo.Win32 demo",
- WINDOW_CAIRO_DEMO_SEQUENCE_COUNT);
- window.button = window_cairo_demo_button;
- window.key = window_cairo_demo_key;
- window.load = window_cairo_demo_load;
- window.render = window_cairo_demo_render;
- window.resize = window_cairo_demo_resize;
- if (! window_cairo_win32_run(&window))
- return g_c3_exit_code;
- c3_window_cairo_clean();
- c3_clean(NULL);
- return 0;
-}
diff --git a/libkc3_window/cairo/win32/sources.mk b/libkc3_window/cairo/win32/sources.mk
deleted file mode 100644
index 9dd7f59..0000000
--- a/libkc3_window/cairo/win32/sources.mk
+++ /dev/null
@@ -1,9 +0,0 @@
-# sources.mk generated by update_sources
-HEADERS = \
- "vk_to_xkbcommon.h" \
- "window_cairo_win32.h" \
-
-SOURCES = \
- "vk_to_xkbcommon.c" \
- "window_cairo_win32.c" \
-
diff --git a/libkc3_window/cairo/win32/sources.sh b/libkc3_window/cairo/win32/sources.sh
deleted file mode 100644
index 7492652..0000000
--- a/libkc3_window/cairo/win32/sources.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-# sources.sh generated by update_sources
-HEADERS='vk_to_xkbcommon.h window_cairo_win32.h '
-SOURCES='vk_to_xkbcommon.c window_cairo_win32.c '
diff --git a/libkc3_window/cairo/win32/update_sources b/libkc3_window/cairo/win32/update_sources
deleted file mode 100755
index abe35fb..0000000
--- a/libkc3_window/cairo/win32/update_sources
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-. ../../../config.subr
-
-echo "$PWD/update_sources"
-
-echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
-echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
-
-HEADERS="$(ls *.h | grep -v '^config.h$')"
-sources HEADERS "$HEADERS"
-
-SOURCES="$(ls *.c)"
-sources SOURCES "$SOURCES"
-
-update_sources_mk
-update_sources_sh
-
-( cd demo && ./update_sources; )
diff --git a/libkc3_window/cairo/win32/vk_to_xkbcommon.c b/libkc3_window/cairo/win32/vk_to_xkbcommon.c
deleted file mode 100644
index 5a7df28..0000000
--- a/libkc3_window/cairo/win32/vk_to_xkbcommon.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <windows.h>
-#include <xkbcommon/xkbcommon.h>
-#include <libkc3/types.h>
-
-u32 vk_to_xkbcommon (u32 vk_key)
-{
- switch (vk_key) {
- case VK_ESCAPE: return XKB_KEY_Escape;
- case VK_F1: return XKB_KEY_F1;
- case VK_F2: return XKB_KEY_F2;
- case VK_F3: return XKB_KEY_F3;
- case VK_F4: return XKB_KEY_F4;
- case VK_F5: return XKB_KEY_F5;
- case VK_F6: return XKB_KEY_F6;
- case VK_F7: return XKB_KEY_F7;
- case VK_F8: return XKB_KEY_F8;
- case VK_F9: return XKB_KEY_F9;
- case VK_F10: return XKB_KEY_F10;
- case VK_F11: return XKB_KEY_F11;
- case VK_F12: return XKB_KEY_F12;
- /*
- case : return XKB_KEY_grave;
- */
- case 0x31: return XKB_KEY_1;
- case 0x32: return XKB_KEY_2;
- case 0x33: return XKB_KEY_3;
- case 0x34: return XKB_KEY_4;
- case 0x35: return XKB_KEY_5;
- case 0x36: return XKB_KEY_6;
- case 0x37: return XKB_KEY_7;
- case 0x38: return XKB_KEY_8;
- case 0x39: return XKB_KEY_9;
- case 0x30: return XKB_KEY_0;
- /*
- case 45: return XKB_KEY_minus;
- case 61: return XKB_KEY_equal;
- */
- case VK_BACK: return XKB_KEY_BackSpace;
- case VK_TAB: return XKB_KEY_Tab;
- case 0x41: return XKB_KEY_a;
- case 0x42: return XKB_KEY_b;
- case 0x43: return XKB_KEY_c;
- case 0x44: return XKB_KEY_d;
- case 0x45: return XKB_KEY_e;
- case 0x46: return XKB_KEY_f;
- case 0x47: return XKB_KEY_g;
- case 0x48: return XKB_KEY_h;
- case 0x49: return XKB_KEY_i;
- case 0x4A: return XKB_KEY_j;
- case 0x4B: return XKB_KEY_k;
- case 0x4C: return XKB_KEY_l;
- case 0x4D: return XKB_KEY_m;
- case 0x4E: return XKB_KEY_n;
- case 0x4F: return XKB_KEY_o;
- case 0x50: return XKB_KEY_p;
- case 0x51: return XKB_KEY_q;
- case 0x52: return XKB_KEY_r;
- case 0x53: return XKB_KEY_s;
- case 0x54: return XKB_KEY_t;
- case 0x55: return XKB_KEY_u;
- case 0x56: return XKB_KEY_v;
- case 0x57: return XKB_KEY_w;
- case 0x58: return XKB_KEY_x;
- case 0x59: return XKB_KEY_y;
- case 0x5A: return XKB_KEY_z;
- /*
- case 91: return XKB_KEY_bracketleft;
- case 93: return XKB_KEY_bracketright;
- case 92: return XKB_KEY_backslash;
- case 59: return XKB_KEY_semicolon;
- case 39: return XKB_KEY_apostrophe;
- */
- case VK_RETURN: return XKB_KEY_Return;
- /*
- case 44: return XKB_KEY_comma;
- case 46: return XKB_KEY_period;
- case 47: return XKB_KEY_slash;
- */
- case VK_SPACE: return XKB_KEY_space;
- case VK_UP: return XKB_KEY_Up;
- case VK_DOWN: return XKB_KEY_Down;
- case VK_LEFT: return XKB_KEY_Left;
- case VK_RIGHT: return XKB_KEY_Right;
- default: break;
- }
- return XKB_KEY_NoSymbol;
-}
diff --git a/libkc3_window/cairo/win32/vk_to_xkbcommon.h b/libkc3_window/cairo/win32/vk_to_xkbcommon.h
deleted file mode 100644
index 2a798b3..0000000
--- a/libkc3_window/cairo/win32/vk_to_xkbcommon.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_WIN32_VK_TO_XKBCOMMON_H
-#define LIBKC3_WINDOW_CAIRO_WIN32_VK_TO_XKBCOMMON_H
-
-#include <libkc3/types.h>
-
-u32 vk_to_xkbcommon (u32 vk_key);
-
-#endif /* LIBKC3_WINDOW_CAIRO_WIN32_VK_TO_XKBCOMMON_H */
diff --git a/libkc3_window/cairo/win32/window_cairo_win32.c b/libkc3_window/cairo/win32/window_cairo_win32.c
deleted file mode 100644
index 1c7827c..0000000
--- a/libkc3_window/cairo/win32/window_cairo_win32.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <stdio.h>
-#include <stdlib.h>
-#include <xkbcommon/xkbcommon.h>
-#include <windows.h>
-#include <cairo.h>
-#include <cairo-win32.h>
-#include <libkc3/kc3.h>
-#include "vk_to_xkbcommon.h"
-#include "window_cairo_win32.h"
-
-bool window_cairo_run (s_window_cairo *window)
-{
- return window_cairo_win32_run(window);
-}
-
-LRESULT CALLBACK window_cairo_win32_proc (HWND hwnd, UINT message,
- WPARAM wParam, LPARAM lParam)
-{
- HBITMAP buffer_hbitmap;
- HDC buffer_hdc;
- cairo_t *cr;
- HDC hdc;
- u32 keysym;
- PAINTSTRUCT ps;
- cairo_surface_t *surface;
- u32 vk;
- s_window_cairo *window;
- HDC window_hdc;
- window = (s_window_cairo *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
- switch (message) {
- case WM_DESTROY:
- printf("WM_DESTROY\n");
- PostQuitMessage(0);
- break;
- case WM_ERASEBKGND:
- return 1;
- case WM_KEYDOWN:
- vk = (u32) wParam;
- keysym = vk_to_xkbcommon(vk);
- if (! window->key(window, keysym)) {
- printf("window->key -> false\n");
- PostQuitMessage(1);
- }
- break;
- case WM_PAINT:
- window_hdc = GetDC(hwnd);
- buffer_hdc = CreateCompatibleDC(window_hdc);
- buffer_hbitmap = CreateCompatibleBitmap(window_hdc, window->w,
- window->h);
- SelectObject(buffer_hdc, buffer_hbitmap);
- surface = cairo_win32_surface_create(buffer_hdc);
- cr = cairo_create(surface);
- window->cr = cr;
- if (! window->render(window)) {
- printf("render -> false\n");
- PostQuitMessage(1);
- }
- cairo_surface_flush(surface);
- cairo_destroy(window->cr);
- cairo_surface_destroy(surface);
- hdc = BeginPaint(hwnd, &ps);
- BitBlt(hdc, 0, 0, window->w, window->h, buffer_hdc, 0, 0, SRCCOPY);
- EndPaint(hwnd, &ps);
- DeleteObject(buffer_hbitmap);
- DeleteDC(buffer_hdc);
- DeleteDC(window_hdc);
- DeleteDC(hdc);
- break;
- case WM_SIZE:
- if (! window->resize(window, LOWORD(lParam), HIWORD(lParam)))
- PostQuitMessage(1);
- window->w = LOWORD(lParam);
- window->h = HIWORD(lParam);
- InvalidateRect(hwnd, NULL, TRUE);
- break;
- default:
- return DefWindowProc(hwnd, message, wParam, lParam);
- }
- return 0;
-}
-
-bool window_cairo_win32_run (s_window_cairo *window)
-{
- HWND hwnd;
- MSG msg;
- s_timespec sleep;
- WNDCLASSEX wc;
- wc.cbSize = sizeof(WNDCLASSEX);
- wc.style = 0;
- wc.lpfnWndProc = window_cairo_win32_proc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hInstance = GetModuleHandle(NULL);
- wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
- wc.lpszMenuName = NULL;
- wc.lpszClassName = "Libc3WindowCairoWin32";
- wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
- if (!RegisterClassEx(&wc)) {
- MessageBox(NULL, "Window Registration Failed!", "Error!",
- MB_ICONEXCLAMATION | MB_OK);
- return 0;
- }
- hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,
- "Libc3WindowCairoWin32",
- window->title,
- WS_OVERLAPPEDWINDOW,
- window->x, window->y, window->w, window->h,
- NULL, NULL, GetModuleHandle(NULL), NULL);
- if (hwnd == NULL) {
- MessageBox(NULL, "Window Creation Failed!", "Error!",
- MB_ICONEXCLAMATION | MB_OK);
- return 0;
- }
- SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) window);
- if (! window->load(window))
- PostQuitMessage(1);
- ShowWindow(hwnd, SW_SHOWDEFAULT);
- UpdateWindow(hwnd);
- while (true) {
- while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
- if (msg.message == WM_QUIT)
- goto quit;
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- sleep.tv_sec = 0;
- sleep.tv_nsec = 1000000000 / 120;
- nanosleep(&sleep, NULL);
- InvalidateRect(hwnd, NULL, TRUE);
- }
- quit:
- return msg.wParam ? false : true;
-}
diff --git a/libkc3_window/cairo/win32/window_cairo_win32.h b/libkc3_window/cairo/win32/window_cairo_win32.h
deleted file mode 100644
index 1df6e49..0000000
--- a/libkc3_window/cairo/win32/window_cairo_win32.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_WIN32_H
-#define LIBKC3_WINDOW_CAIRO_WIN32_H
-
-#include "../window_cairo.h"
-
-bool window_cairo_win32_run (s_window_cairo *window);
-
-#endif /* LIBKC3_WINDOW_CAIRO_XCB_H */
diff --git a/libkc3_window/cairo/window_cairo.c b/libkc3_window/cairo/window_cairo.c
deleted file mode 100644
index 8632633..0000000
--- a/libkc3_window/cairo/window_cairo.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <assert.h>
-#include <stdlib.h>
-#include <xkbcommon/xkbcommon.h>
-#include <libkc3/tag.h>
-#include "../window.h"
-#include "window_cairo.h"
-
-void kc3_window_cairo_clean (void)
-{
-}
-
-void kc3_window_cairo_init (void)
-{
-}
-
-void window_cairo_clean (s_window_cairo *window)
-{
- window_clean((s_window *) window);
-}
-
-s_window_cairo * window_cairo_init (s_window_cairo *window,
- sw x, sw y, uw w, uw h,
- const char *title,
- uw sequence_count)
-{
- s_window_cairo tmp = {0};
- assert(window);
- title = title ? title : "KC3.Window.Cairo";
- window_init((s_window *) &tmp, x, y, w, h, title, sequence_count);
- tmp.button = window_cairo_button_default;
- tmp.key = window_cairo_key_default;
- tmp.load = window_cairo_load_default;
- tmp.motion = window_cairo_motion_default;
- tmp.render = window_cairo_render_default;
- tmp.resize = window_cairo_resize_default;
- *window = tmp;
- return window;
-}
-
-bool window_cairo_button_default (s_window_cairo *window, u8 button,
- sw x, sw y)
-{
- assert(window);
- (void) window;
- (void) button;
- (void) x;
- (void) y;
- printf("window_cairo_button_default: %d (%ld, %ld)\n",
- (int) button, x, y);
- return true;
-}
-
-bool window_cairo_key_default (s_window_cairo *window, uw keysym)
-{
- char keysym_name[64];
- assert(window);
- (void) window;
- xkb_keysym_get_name(keysym, keysym_name, sizeof(keysym_name));
- printf("window_cairo_key_default: %lu %s\n", keysym, keysym_name);
- return true;
-}
-
-bool window_cairo_load_default (s_window_cairo *window)
-{
- assert(window);
- (void) window;
- printf("window_cairo_load_default\n");
- return true;
-}
-
-bool window_cairo_motion_default (s_window_cairo *window, sw x, sw y)
-{
- assert(window);
- (void) window;
- (void) x;
- (void) y;
- /*
- printf("window_cairo_motion_default (%ld, %ld)\n", x, y);
- */
- return true;
-}
-
-bool window_cairo_render_default (s_window_cairo *window)
-{
- cairo_t *cr;
- assert(window);
- cr = window->cr;
- assert(cr);
- cairo_set_source_rgb(cr, 1, 1, 1);
- cairo_rectangle(cr, 0, 0, window->w, window->h);
- cairo_fill(cr);
- printf("window_cairo_render_default\n");
- return true;
-}
-
-bool window_cairo_resize_default (s_window_cairo *window, uw w, uw h)
-{
- assert(window);
- (void) window;
- (void) w;
- (void) h;
- printf("window_cairo_resize_default: %lu x %lu\n", w, h);
- return true;
-}
diff --git a/libkc3_window/cairo/window_cairo.h b/libkc3_window/cairo/window_cairo.h
deleted file mode 100644
index 786a969..0000000
--- a/libkc3_window/cairo/window_cairo.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_H
-#define LIBKC3_WINDOW_CAIRO_H
-
-#include "types.h"
-
-/* Library functions, call kc3_window_cairo_init at program start,
- and kc3_window_cairo_clean at program end. */
-void kc3_window_cairo_clean (void);
-void kc3_window_cairo_init (void);
-
-/* Stack-allocation compatible functions, call window_cairo_clean
- after use. */
-void window_cairo_clean (s_window_cairo *window);
-s_window_cairo * window_cairo_init (s_window_cairo *window,
- sw x, sw y, uw w, uw h,
- const char *title,
- uw sequence_count);
-bool window_cairo_run (s_window_cairo *window);
-
-/* Callbacks. */
-bool window_cairo_button_default (s_window_cairo *window, u8 button,
- sw x, sw y);
-bool window_cairo_key_default (s_window_cairo *window, uw keysym);
-bool window_cairo_load_default (s_window_cairo *window);
-bool window_cairo_motion_default (s_window_cairo *window, sw x, sw y);
-bool window_cairo_render_default (s_window_cairo *window);
-bool window_cairo_resize_default (s_window_cairo *window, uw w, uw h);
-
-#endif /* LIBKC3_WINDOW_CAIRO_H */
diff --git a/libkc3_window/cairo/xcb/Makefile b/libkc3_window/cairo/xcb/Makefile
deleted file mode 100644
index 140213f..0000000
--- a/libkc3_window/cairo/xcb/Makefile
+++ /dev/null
@@ -1,104 +0,0 @@
-## kc3
-## Copyright 2022-2024 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.
-
-CLEANFILES = *.a *.gcno *.la .libs *.lo *.o
-
-CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
-
-CLEANFILES += ${CLEANFILES_COV}
-
-DISTCLEANFILES = ${CLEANFILES} config.h config.mk
-
-build:
- ${MAKE} ${LIB}
- ${MAKE} -C demo build
-
-all:
- ${MAKE} build
- if ${HAVE_GCOV}; then ${MAKE} cov; fi
- ${MAKE} debug
- if ${HAVE_ASAN}; then ${MAKE} asan; fi
-
-asan:
- ${MAKE} ${LIB_ASAN}
- ${MAKE} -C demo asan
-
-clean:
- rm -rf ${CLEANFILES}
- ${MAKE} -C demo clean
-
-clean_cov:
- rm -rf ${CLEANFILES_COV}
- ${MAKE} -C demo clean_cov
-
-cov:
- ${MAKE} ${LIB_COV}
- ${MAKE} -C demo cov
-
-debug:
- ${MAKE} ${LIB_DEBUG}
- ${MAKE} -C demo debug
-
-demo: build
- ${MAKE} -C demo demo
-
-demo_asan: asan
- ${MAKE} -C demo demo_asan
-
-demo_cov: cov
- ${MAKE} -C demo demo_cov
-
-demo_debug: debug
- ${MAKE} -C demo demo_debug
-
-distclean:
- rm -rf ${DISTCLEANFILES}
- ${MAKE} -C demo distclean
-
-gdb_demo: debug
- ${MAKE} -C demo gdb_demo
-
-install:
- ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0755 -d ${prefix}/include/libc3/window/cairo/xcb
- ${LIBTOOL} --tag=CC --mode=install ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0644 ${HEADERS} ${prefix}/include/libc3/window/cairo/xcb
- ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0755 -d ${prefix}/lib
- ${LIBTOOL} --tag=CC --mode=install ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0644 ${LIB} ${prefix}/lib
- ${LIBTOOL} --finish ${prefix}/lib
- ${MAKE} -C demo install
-
-test: build
- ${MAKE} -C demo test
-
-update_sources:
- ./update_sources
-
-.PHONY: \
- all \
- asan \
- build \
- clean \
- cov \
- debug \
- demo \
- demo_asan \
- demo_cov \
- demo_debug \
- distclean \
- gdb_demo \
- gen \
- install \
- lldb_demo \
- test \
- update_sources
-
-include config.mk
-include sources.mk
diff --git a/libkc3_window/cairo/xcb/configure b/libkc3_window/cairo/xcb/configure
deleted file mode 100755
index 8666872..0000000
--- a/libkc3_window/cairo/xcb/configure
+++ /dev/null
@@ -1,123 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-set -e
-
-echo "$PWD/configure"
-
-export SRC_TOP="$(dirname "$PWD")"
-
-CONFIG_H_PREFIX=LIBKC3_WINDOW_CAIRO_XCB_
-
-. ../../../config.subr
-
-LIB=libkc3_window_cairo_xcb.la
-LIB_ASAN=libkc3_window_cairo_xcb_asan.la
-LIB_COV=libkc3_window_cairo_xcb_cov.la
-LIB_DEBUG=libkc3_window_cairo_xcb_debug.la
-
-echo "LIB = $LIB" >> ${CONFIG_MK}
-echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
-echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
-echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
-
-. ./sources.sh
-
-OBJECTS="$(c2ext .main.lo "$SOURCES")"
-echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
-OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
-OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
-OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
-
-# Common config for all targets
-CPPFLAGS="$CPPFLAGS -I../../.."
-CFLAGS="$CFLAGS -W -Wall -Werror -std=c11 -pedantic -pipe"
-LDFLAGS="--shared ${LDFLAGS}"
-config_asan
-config_gnu
-config_i386
-pkg_config libbsd-overlay
-pkg_config libffi
-pkg_config libmd
-pkg_config xcb
-pkg_config xkbcommon
-pkg_config cairo
-pkg_config cairo-xcb
-config_define PREFIX "\"${PREFIX}\""
-update_config_h
-LIBS="$LIBS -lxkbcommon -lxkbcommon-x11"
-LIBS="$LIBS -rpath ${PREFIX}/lib"
-
-# Address Sanitizer config
-CPPFLAGS_ASAN="$CPPFLAGS"
-CFLAGS_ASAN="$CFLAGS -DDEBUG -O1 -g"
-CFLAGS_ASAN="$CFLAGS_ASAN -fsanitize=address -fno-omit-frame-pointer"
-LDFLAGS_ASAN="$LDFLAGS"
-LIBS_LOCAL_ASAN="../libkc3_window_cairo_asan.la"
-LIBS_ASAN="$LIBS_LOCAL_ASAN $LIBS"
-
-# Coverage config
-CPPFLAGS_COV="$CPPFLAGS"
-CFLAGS_COV="$CFLAGS -DDEBUG --coverage"
-LDFLAGS_COV="$LDFLAGS"
-LIBS_LOCAL_COV="../libkc3_window_cairo_cov.la"
-LIBS_COV="$LIBS_LOCAL_COV $LIBS"
-
-# Debug config
-CPPFLAGS_DEBUG="$CPPFLAGS"
-CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
-LDFLAGS_DEBUG="$LDFLAGS"
-LIBS_LOCAL_DEBUG="../libkc3_window_cairo_debug.la"
-LIBS_DEBUG="$LIBS_LOCAL_DEBUG $LIBS"
-
-# Main config
-DEFAULT_CFLAGS="-O2 -fPIC"
-if [ "x$ENV_CFLAGS" = "x" ]; then
- CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
-fi
-CFLAGS="$CFLAGS -DNDEBUG"
-LIBS_LOCAL="../libkc3_window_cairo.la"
-LIBS="$LIBS_LOCAL $LIBS"
-
-echo "LIB = $LIB" >> ${CONFIG_MK}
-echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
-echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
-echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
-echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
-echo "LIBS = $LIBS" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
-echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
-echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
-echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
-echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
-echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
-
-update_build
-update_build_lib
-
-build_lo
-build_lib
-
-update_config_mk
-env_reset
-
-config_subdirs demo
diff --git a/libkc3_window/cairo/xcb/demo/Makefile b/libkc3_window/cairo/xcb/demo/Makefile
deleted file mode 100644
index 30365c8..0000000
--- a/libkc3_window/cairo/xcb/demo/Makefile
+++ /dev/null
@@ -1,99 +0,0 @@
-## kc3
-## Copyright 2022-2024 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.
-
-CLEANFILES = *.a ${PROG} ${PROG_ASAN} ${PROG_COV} ${PROG_DEBUG} *.css \
- *.gcno *.html *.o .libs *.lo
-
-CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
-CLEANFILES += ${CLEANFILES_COV}
-
-DISTCLEANFILES = ${CLEANFILES} config.mk
-
-build:
- ${MAKE} ${PROG}
-
-all:
- ${MAKE} build
- if ${HAVE_GCOV}; then ${MAKE} cov; fi
- ${MAKE} debug
- if ${HAVE_ASAN}; then ${MAKE} asan; fi
-
-asan:
- ${MAKE} ${PROG_ASAN}
-
-clean:
- rm -rf ${CLEANFILES}
-
-clean_cov:
- rm -rf ${CLEANFILES_COV}
-
-cov:
- ${MAKE} ${PROG_COV}
-
-debug:
- ${MAKE} ${PROG_DEBUG}
-
-demo:
- ${MAKE} ${PROG}
- time ./${PROG}
-
-demo_asan:
- ${MAKE} ${PROG_ASAN}
- time ./${PROG_ASAN}
-
-demo_cov:
- ${MAKE} ${PROG_COV}
- time ./${PROG_COV}
-
-demo_debug:
- ${MAKE} ${PROG_DEBUG}
- time ./${PROG_DEBUG}
-
-distclean:
- rm -rf ${DISTCLEANFILES}
-
-gcovr:
- gcovr --gcov-executable ${GCOV} --html-details ${PROG}.html
-
-gdb_demo: debug
- if [ -f ${PROG_DEBUG}.core ]; then gdb .libs/${PROG_DEBUG} ${PROG_DEBUG}.core; else gdb .libs/${PROG_DEBUG}; fi
-
-install:
- install -m 755 -d ${prefix}/bin
- install -m 755 ${PROG} ${prefix}/bin/${PROG}
-
-lldb_demo: debug
- if [ -f ${PROG_DEBUG}.core ]; then lldb .libs/${PROG_DEBUG} ${PROG_DEBUG}.core; else lldb .libs/${PROG_DEBUG}; fi
-
-update_sources:
- ./update_sources
-
-.PHONY: \
- all \
- asan \
- build \
- clean \
- clean_cov \
- cov \
- debug \
- demo \
- demo_asan \
- demo_cov \
- demo_debug \
- distclean \
- gdb_demo \
- install \
- lldb_demo \
- update_sources \
-
-include config.mk
-include sources.mk
diff --git a/libkc3_window/cairo/xcb/demo/configure b/libkc3_window/cairo/xcb/demo/configure
deleted file mode 100755
index 9e16ca9..0000000
--- a/libkc3_window/cairo/xcb/demo/configure
+++ /dev/null
@@ -1,132 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-set -e
-
-echo "$PWD/configure"
-
-export SRC_TOP="$(dirname "$PWD")"
-
-. ../../../../config.subr
-
-PROG=kc3_window_cairo_xcb_demo
-PROG_ASAN=kc3_window_cairo_xcb_demo_asan
-PROG_COV=kc3_window_cairo_xcb_demo_cov
-PROG_DEBUG=kc3_window_cairo_xcb_demo_debug
-
-echo "PROG = $PROG" >> ${CONFIG_MK}
-echo "PROG_ASAN = $PROG_ASAN" >> ${CONFIG_MK}
-echo "PROG_COV = $PROG_COV" >> ${CONFIG_MK}
-echo "PROG_DEBUG = $PROG_DEBUG" >> ${CONFIG_MK}
-
-. ./sources.sh
-
-OBJECTS="$(c2ext .main.lo "$SOURCES")"
-echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
-
-OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
-echo "OBJECTS_ASAN = $OBJECTS_ASAN" >> ${CONFIG_MK}
-
-if $HAVE_GCOV; then
- OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
- echo "OBJECTS_COV = $OBJECTS_COV" >> ${CONFIG_MK}
-fi
-
-OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
-echo "OBJECTS_DEBUG = $OBJECTS_DEBUG" >> ${CONFIG_MK}
-
-# Common config for all targets
-CFLAGS="$CFLAGS -W -Wall -Werror -std=c11 -pedantic"
-CPPFLAGS="$CPPFLAGS -I../../../.."
-config_asan
-config_gnu
-config_i386
-pkg_config libbsd-overlay
-pkg_config libffi
-pkg_config libmd
-pkg_config xcb
-pkg_config cairo
-LIBS="$LIBS"
-
-# Asan config
-CPPFLAGS_ASAN="$CPPFLAGS"
-CFLAGS_ASAN="$CFLAGS -DDEBUG -O1 -g"
-CFLAGS_ASAN="$CFLAGS_ASAN -fsanitize=address -fno-omit-frame-pointer"
-LDFLAGS_ASAN="$LDFLAGS"
-LOCAL_LIBS_ASAN="../../../../libkc3/libkc3_asan.la"
-LOCAL_LIBS_ASAN="$LOCAL_LIBS_ASAN ../../../libkc3_window_asan.la"
-LOCAL_LIBS_ASAN="$LOCAL_LIBS_ASAN ../../libkc3_window_cairo_asan.la"
-LOCAL_LIBS_ASAN="$LOCAL_LIBS_ASAN ../../demo/libkc3_window_cairo_demo_asan.la"
-LOCAL_LIBS_ASAN="$LOCAL_LIBS_ASAN ../libkc3_window_cairo_xcb_asan.la"
-LIBS_ASAN="$LOCAL_LIBS_ASAN $LIBS"
-
-# Coverage config
-CPPFLAGS_COV="$CPPFLAGS"
-CFLAGS_COV="$CFLAGS -DDEBUG -fprofile-arcs -ftest-coverage"
-LDFLAGS_COV="$LDFLAGS --coverage"
-LOCAL_LIBS_COV="../../../../libkc3/libkc3_cov.la"
-LOCAL_LIBS_COV="$LOCAL_LIBS_COV ../../../libkc3_window_cov.la"
-LOCAL_LIBS_COV="$LOCAL_LIBS_COV ../../libkc3_window_cairo_cov.la"
-LOCAL_LIBS_COV="$LOCAL_LIBS_COV ../../demo/libkc3_window_cairo_demo_cov.la"
-LOCAL_LIBS_COV="$LOCAL_LIBS_COV ../libkc3_window_cairo_xcb_cov.la"
-LIBS_COV="$LOCAL_LIBS_COV $LIBS -lgcov"
-
-# Debug config
-CPPFLAGS_DEBUG="$CPPFLAGS"
-CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
-LDFLAGS_DEBUG="$LDFLAGS"
-LOCAL_LIBS_DEBUG="../../../../libkc3/libkc3_debug.la"
-LOCAL_LIBS_DEBUG="$LOCAL_LIBS_DEBUG ../../../libkc3_window_debug.la"
-LOCAL_LIBS_DEBUG="$LOCAL_LIBS_DEBUG ../../libkc3_window_cairo_debug.la"
-LOCAL_LIBS_DEBUG="$LOCAL_LIBS_DEBUG ../../demo/libkc3_window_cairo_demo_debug.la"
-LOCAL_LIBS_DEBUG="$LOCAL_LIBS_DEBUG ../libkc3_window_cairo_xcb_debug.la"
-LIBS_DEBUG="$LOCAL_LIBS_DEBUG $LIBS"
-
-# Main config
-DEFAULT_CFLAGS="-O2 -pipe -fPIC"
-if [ "x$ENV_CFLAGS" = "x" ]; then
- CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
-fi
-CFLAGS="$CFLAGS -DNDEBUG"
-LOCAL_LIBS="../../../../libkc3/libkc3.la"
-LOCAL_LIBS="$LOCAL_LIBS ../../../libkc3_window.la"
-LOCAL_LIBS="$LOCAL_LIBS ../../libkc3_window_cairo.la"
-LOCAL_LIBS="$LOCAL_LIBS ../../demo/libkc3_window_cairo_demo.la"
-LOCAL_LIBS="$LOCAL_LIBS ../libkc3_window_cairo_xcb.la"
-LIBS="$LOCAL_LIBS $LIBS"
-
-echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
-echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
-echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
-echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
-echo "LIBS = $LIBS" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
-echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
-echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
-
-update_build
-update_build_prog
-
-build_lo
-build_prog
-
-update_config_mk
diff --git a/libkc3_window/cairo/xcb/demo/sources.mk b/libkc3_window/cairo/xcb/demo/sources.mk
deleted file mode 100644
index e48fc91..0000000
--- a/libkc3_window/cairo/xcb/demo/sources.mk
+++ /dev/null
@@ -1,7 +0,0 @@
-# sources.mk generated by update_sources
-HEADERS = \
- "" \
-
-SOURCES = \
- "window_cairo_xcb_demo.c" \
-
diff --git a/libkc3_window/cairo/xcb/demo/sources.sh b/libkc3_window/cairo/xcb/demo/sources.sh
deleted file mode 100644
index 4fbe5a1..0000000
--- a/libkc3_window/cairo/xcb/demo/sources.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-# sources.sh generated by update_sources
-HEADERS=' '
-SOURCES='window_cairo_xcb_demo.c '
diff --git a/libkc3_window/cairo/xcb/demo/update_sources b/libkc3_window/cairo/xcb/demo/update_sources
deleted file mode 100755
index 904d0bd..0000000
--- a/libkc3_window/cairo/xcb/demo/update_sources
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-. ../../../../config.subr
-
-echo "$PWD/update_sources"
-
-echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
-echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
-
-HEADERS=
-#HEADERS="$(ls *.h | grep -v '^config.h$')"
-sources HEADERS "$HEADERS"
-
-SOURCES="$(ls *.c)"
-sources SOURCES "$SOURCES"
-
-update_sources_mk
-update_sources_sh
diff --git a/libkc3_window/cairo/xcb/demo/window_cairo_xcb_demo.c b/libkc3_window/cairo/xcb/demo/window_cairo_xcb_demo.c
deleted file mode 100644
index bce4056..0000000
--- a/libkc3_window/cairo/xcb/demo/window_cairo_xcb_demo.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <stdio.h>
-#include <stdlib.h>
-#include <libkc3/kc3.h>
-#include "../../window_cairo.h"
-#include "../../demo/window_cairo_demo.h"
-#include "../window_cairo_xcb.h"
-
-int main (int argc, char **argv)
-{
- s_window_cairo window;
- if (! kc3_init(NULL, &argc, &argv)) {
- err_puts("kc3_init");
- return 1;
- }
- kc3_window_cairo_init();
- window_cairo_init(&window, 0, 0, 800, 600,
- "KC3.Window.Cairo.XCB demo",
- WINDOW_CAIRO_DEMO_SEQUENCE_COUNT);
- window.button = window_cairo_demo_button;
- window.key = window_cairo_demo_key;
- window.load = window_cairo_demo_load;
- window.render = window_cairo_demo_render;
- window.resize = window_cairo_demo_resize;
- window.unload = window_cairo_demo_unload;
- if (! window_cairo_xcb_run(&window)) {
- err_puts("window_cairo_xcb_run -> false");
- window_cairo_clean(&window);
- kc3_clean(NULL);
- return g_kc3_exit_code;
- }
- window_cairo_clean(&window);
- kc3_clean(NULL);
- return 0;
-}
diff --git a/libkc3_window/cairo/xcb/sources.mk b/libkc3_window/cairo/xcb/sources.mk
deleted file mode 100644
index aa817cf..0000000
--- a/libkc3_window/cairo/xcb/sources.mk
+++ /dev/null
@@ -1,7 +0,0 @@
-# sources.mk generated by update_sources
-HEADERS = \
- "window_cairo_xcb.h" \
-
-SOURCES = \
- "window_cairo_xcb.c" \
-
diff --git a/libkc3_window/cairo/xcb/sources.sh b/libkc3_window/cairo/xcb/sources.sh
deleted file mode 100644
index 7890149..0000000
--- a/libkc3_window/cairo/xcb/sources.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-# sources.sh generated by update_sources
-HEADERS='window_cairo_xcb.h '
-SOURCES='window_cairo_xcb.c '
diff --git a/libkc3_window/cairo/xcb/update_sources b/libkc3_window/cairo/xcb/update_sources
deleted file mode 100755
index abe35fb..0000000
--- a/libkc3_window/cairo/xcb/update_sources
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-. ../../../config.subr
-
-echo "$PWD/update_sources"
-
-echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
-echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
-
-HEADERS="$(ls *.h | grep -v '^config.h$')"
-sources HEADERS "$HEADERS"
-
-SOURCES="$(ls *.c)"
-sources SOURCES "$SOURCES"
-
-update_sources_mk
-update_sources_sh
-
-( cd demo && ./update_sources; )
diff --git a/libkc3_window/cairo/xcb/window_cairo_xcb.c b/libkc3_window/cairo/xcb/window_cairo_xcb.c
deleted file mode 100644
index 4b41263..0000000
--- a/libkc3_window/cairo/xcb/window_cairo_xcb.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <stdio.h>
-#include <stdlib.h>
-#include <cairo/cairo-xcb.h>
-#include <libkc3/kc3.h>
-#include <xcb/xcb.h>
-#include <xkbcommon/xkbcommon.h>
-#include <xkbcommon/xkbcommon-x11.h>
-#include "window_cairo_xcb.h"
-
-bool window_cairo_run (s_window_cairo *window)
-{
- return window_cairo_xcb_run(window);
-}
-
-bool window_cairo_xcb_event (s_window_cairo *window,
- xcb_connection_t *conn,
- xcb_screen_t *screen,
- xcb_visualtype_t *visual,
- xcb_pixmap_t *pixmap,
- cairo_surface_t **surface,
- xcb_window_t xcb_window,
- xcb_generic_event_t *event,
- struct xkb_state *xkb_state)
-{
- xcb_button_press_event_t *event_button;
- xcb_configure_notify_event_t *event_config;
- xcb_key_press_event_t *event_key;
- xcb_motion_notify_event_t *event_motion;
- switch (event->response_type & ~0x80) {
- case XCB_BUTTON_PRESS:
- event_button = (xcb_button_press_event_t *) event;
- if (! window->button(window, event_button->detail,
- event_button->event_x,
- event_button->event_y))
- goto ko;
- break;
- case XCB_EXPOSE:
- if (! window->render(window))
- goto ko;
- xcb_gcontext_t gc = xcb_generate_id(conn);
- u32 gc_mask = XCB_GC_GRAPHICS_EXPOSURES;
- u32 gc_values[1] = {0};
- xcb_create_gc(conn, gc, xcb_window, gc_mask, gc_values);
- xcb_copy_area(conn, *pixmap, xcb_window, gc,
- 0, 0, 0, 0, window->w, window->h);
- xcb_flush(conn);
- break;
- case XCB_CONFIGURE_NOTIFY:
- event_config = (xcb_configure_notify_event_t *) event;
- if (! window->resize(window, event_config->width,
- event_config->height))
- goto ko;
- window->w = event_config->width;
- window->h = event_config->height;
- cairo_destroy(window->cr);
- cairo_surface_destroy(*surface);
- xcb_free_pixmap(conn, *pixmap);
- *pixmap = xcb_generate_id(conn);
- xcb_create_pixmap(conn, screen->root_depth, *pixmap, xcb_window,
- window->w, window->h);
- *surface = cairo_xcb_surface_create(conn, *pixmap, visual, window->w,
- window->h);
- window->cr = cairo_create(*surface);
- break;
- case XCB_KEY_PRESS:
- event_key = (xcb_key_press_event_t *) event;
- xkb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state, event_key->detail);
- if (! window->key(window, sym))
- goto ko;
- break;
- case XCB_MOTION_NOTIFY:
- event_motion = (xcb_motion_notify_event_t *) event;
- if (! window->motion(window, event_motion->event_x,
- event_motion->event_y))
- goto ko;
- break;
- default:
- printf("event type %d\n", event->response_type & ~0x80);
- }
- free(event);
- return true;
- ko:
- free(event);
- return false;
-}
-
-bool window_cairo_xcb_run (s_window_cairo *window)
-{
- xcb_connection_t *conn;
- xcb_generic_event_t *event;
- xcb_pixmap_t pixmap;
- bool r;
- xcb_screen_t *screen;
- xcb_visualtype_t *screen_visual;
- s_timespec sleep;
- cairo_surface_t *surface;
- u32 value_mask;
- u32 *value_list;
- xcb_window_t xcb_window;
- struct xkb_context *xkb_ctx;
- int32_t xkb_device_id;
- struct xkb_keymap *xkb_keymap;
- struct xkb_state *xkb_state;
- conn = xcb_connect(NULL, NULL);
- if (xcb_connection_has_error(conn)) {
- fprintf(stderr, "Error opening display.\n");
- return false;
- }
- xkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
- if (!xkb_ctx) {
- fprintf(stderr, "Failed to create XKB context\n");
- return false;
- }
- xkb_x11_setup_xkb_extension(conn, 1, 0, 0, NULL, NULL, NULL, NULL);
- xkb_device_id = xkb_x11_get_core_keyboard_device_id(conn);
- if (xkb_device_id == -1) {
- fprintf(stderr, "Failed to get XKB device ID\n");
- return false;
- }
- xkb_keymap =
- xkb_x11_keymap_new_from_device(xkb_ctx, conn, xkb_device_id,
- XKB_KEYMAP_COMPILE_NO_FLAGS);
- xkb_state = xkb_x11_state_new_from_device(xkb_keymap, conn,
- xkb_device_id);
- screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
- screen_visual = xcb_screen_visual_type(screen);
- xcb_window = xcb_generate_id(conn);
- value_mask = XCB_CW_EVENT_MASK;
- value_list = (u32[]) {XCB_EVENT_MASK_BUTTON_PRESS |
- XCB_EVENT_MASK_EXPOSURE |
- XCB_EVENT_MASK_KEY_PRESS |
- XCB_EVENT_MASK_POINTER_MOTION |
- XCB_EVENT_MASK_STRUCTURE_NOTIFY};
- xcb_create_window(conn, XCB_COPY_FROM_PARENT, xcb_window,
- screen->root, window->x, window->y,
- window->w, window->h, 0,
- XCB_WINDOW_CLASS_INPUT_OUTPUT,
- screen->root_visual,
- value_mask, value_list);
- xcb_change_property(conn, XCB_PROP_MODE_REPLACE, xcb_window,
- XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
- strlen(window->title), window->title);
- xcb_map_window(conn, xcb_window);
- pixmap = xcb_generate_id(conn);
- xcb_create_pixmap(conn, screen->root_depth, pixmap, xcb_window,
- window->w, window->h);
- surface = cairo_xcb_surface_create(conn, pixmap, screen_visual,
- window->w, window->h);
- window->cr = cairo_create(surface);
- xcb_flush(conn);
- if (! (r = window->load(window)))
- goto clean;
- while (1) {
- if ((event = xcb_poll_for_event(conn))) {
- if (! (r = window_cairo_xcb_event(window, conn, screen,
- screen_visual, &pixmap,
- &surface, xcb_window,
- event, xkb_state)))
- goto clean;
- }
- else {
- sleep.tv_sec = 0;
- sleep.tv_nsec = 1000000000 / 120;
- nanosleep(&sleep, NULL);
- xcb_expose_event_t event = {0};
- event.response_type = XCB_EXPOSE;
- event.window = xcb_window;
- event.x = 0;
- event.y = 0;
- event.width = window->w;
- event.height = window->h;
- event.count = 0;
- xcb_send_event(conn, false, xcb_window, XCB_EVENT_MASK_EXPOSURE, (const char *)&event);
- xcb_flush(conn);
- }
- }
- clean:
- cairo_surface_destroy(surface);
- cairo_destroy(window->cr);
- xkb_state_unref(xkb_state);
- xkb_keymap_unref(xkb_keymap);
- xkb_context_unref(xkb_ctx);
- xcb_disconnect(conn);
- return r;
-}
-
-xcb_visualtype_t * xcb_screen_visual_type (xcb_screen_t *screen)
-{
- xcb_depth_iterator_t depth_iter;
- xcb_visualtype_iterator_t visual_iter;
- depth_iter = xcb_screen_allowed_depths_iterator(screen);
- while (depth_iter.rem) {
- visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
- while (visual_iter.rem) {
- if (screen->root_visual == visual_iter.data->visual_id) {
- return visual_iter.data;
- }
- xcb_visualtype_next(&visual_iter);
- }
- xcb_depth_next(&depth_iter);
- }
- return NULL;
-}
diff --git a/libkc3_window/cairo/xcb/window_cairo_xcb.h b/libkc3_window/cairo/xcb/window_cairo_xcb.h
deleted file mode 100644
index 6347bec..0000000
--- a/libkc3_window/cairo/xcb/window_cairo_xcb.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_XCB_H
-#define LIBKC3_WINDOW_CAIRO_XCB_H
-
-#include <xcb/xcb.h>
-#include "../window_cairo.h"
-
-bool window_cairo_xcb_run (s_window_cairo *window);
-
-xcb_visualtype_t * xcb_screen_visual_type (xcb_screen_t *screen);
-
-#endif /* LIBKC3_WINDOW_CAIRO_XCB_H */
diff --git a/libkc3_window/configure b/libkc3_window/configure
deleted file mode 100755
index 52f09e4..0000000
--- a/libkc3_window/configure
+++ /dev/null
@@ -1,136 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-set -e
-
-echo "$PWD/configure"
-
-export SRC_TOP="$(dirname "$PWD")"
-
-CONFIG_H_PREFIX=LIBKC3_WINDOW_
-
-. ../config.subr
-
-LIB=libkc3_window.la
-LIB_ASAN=libkc3_window_asan.la
-LIB_COV=libkc3_window_cov.la
-LIB_DEBUG=libkc3_window_debug.la
-
-echo "LIB = $LIB" >> ${CONFIG_MK}
-echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
-echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
-echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
-
-. ./sources.sh
-
-OBJECTS="$(c2ext .main.lo "$SOURCES")"
-echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
-OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
-OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
-OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
-
-# Common config for all targets
-CPPFLAGS="-I.. $CPPFLAGS"
-CFLAGS="$CFLAGS -W -Wall -Werror -std=c11 -pedantic -pipe"
-LDFLAGS="--shared ${LDFLAGS} -rdynamic"
-config_asan
-config_gnu
-config_i386
-pkg_config libbsd-overlay
-pkg_config libffi
-pkg_config libmd
-config_define PREFIX "\"${PREFIX}\""
-LIBS="$LIBS -rpath ${PREFIX}/lib"
-
-# Address Sanitizer config
-CPPFLAGS_ASAN="$CPPFLAGS"
-CFLAGS_ASAN="$CFLAGS -DDEBUG -O1 -g"
-CFLAGS_ASAN="$CFLAGS_ASAN -fsanitize=address -fno-omit-frame-pointer"
-LDFLAGS_ASAN="$LDFLAGS"
-LIBS_LOCAL_ASAN="../libkc3/libkc3_asan.la"
-LIBS_ASAN="$LIBS_LOCAL_ASAN $LIBS"
-
-# Coverage config
-CPPFLAGS_COV="$CPPFLAGS"
-CFLAGS_COV="$CFLAGS --coverage"
-LDFLAGS_COV="$LDFLAGS"
-LIBS_LOCAL_COV="../libkc3/libkc3_cov.la"
-LIBS_COV="$LIBS_LOCAL_COV $LIBS"
-
-# Debug config
-CPPFLAGS_DEBUG="$CPPFLAGS"
-CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
-LDFLAGS_DEBUG="$LDFLAGS"
-LIBS_LOCAL_DEBUG="../libkc3/libkc3_debug.la"
-LIBS_DEBUG="$LIBS_LOCAL_DEBUG $LIBS"
-
-# Main config
-DEFAULT_CFLAGS="-O2 -pipe -fPIC"
-if [ "x$ENV_CFLAGS" = "x" ]; then
- CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
-fi
-CFLAGS="$CFLAGS -DNDEBUG"
-LIBS_LOCAL="../libkc3/libkc3.la"
-LIBS="$LIBS_LOCAL $LIBS"
-
-echo "LIB = $LIB" >> ${CONFIG_MK}
-echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
-echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
-echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
-echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
-echo "LIBS = $LIBS" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
-echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
-echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
-echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
-echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
-echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
-
-update_build
-update_build_lib
-
-build_lo
-build_lib
-
-if pkg-config cairo; then
- HAVE_CAIRO=true
-else
- HAVE_CAIRO=false
-fi
-echo "HAVE_CAIRO = $HAVE_CAIRO" >> ${CONFIG_MK}
-
-if pkg-config sdl2; then
- HAVE_SDL2=true
-else
- HAVE_SDL2=false
-fi
-echo "HAVE_SDL2 = $HAVE_SDL2" >> ${CONFIG_MK}
-
-update_config_mk
-env_reset
-
-if ${HAVE_CAIRO}; then
- config_subdirs cairo
-fi
-if ${HAVE_SDL2}; then
- config_subdirs sdl2
-fi
diff --git a/libkc3_window/sdl2/Makefile b/libkc3_window/sdl2/Makefile
deleted file mode 100644
index b9b5416..0000000
--- a/libkc3_window/sdl2/Makefile
+++ /dev/null
@@ -1,107 +0,0 @@
-## kc3
-## Copyright 2022-2024 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.
-
-CLEANFILES = *.a *.gcno *.la .libs *.lo *.o
-
-CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
-
-CLEANFILES += ${CLEANFILES_COV}
-
-DISTCLEANFILES = ${CLEANFILES} config.h config.mk
-
-build:
- ${MAKE} ${LIB}
- ${MAKE} -C demo build
-
-all:
- ${MAKE} build
- ${MAKE} debug
- if ${HAVE_ASAN}; then ${MAKE} asan; fi
- if ${HAVE_GCOV}; then ${MAKE} cov; fi
-
-asan:
- ${MAKE} ${LIB_ASAN}
- ${MAKE} -C demo asan
-
-clean:
- rm -rf ${CLEANFILES}
- ${MAKE} -C demo clean
-
-clean_cov:
- ${MAKE} -C demo clean_cov
-
-cov:
- ${MAKE} ${LIB_COV}
- ${MAKE} -C demo cov
-
-debug:
- ${MAKE} ${LIB_DEBUG}
- ${MAKE} -C demo debug
-
-demo: build
- ${MAKE} -C demo demo
-
-demo_asan: asan
- ${MAKE} -C demo demo_asan
-
-demo_cov: cov
- ${MAKE} -C demo demo_cov
-
-demo_debug: debug
- ${MAKE} -C demo demo_debug
-
-distclean:
- rm -rf ${DISTCLEANFILES}
- ${MAKE} -C demo distclean
-
-gcovr:
- ${MAKE} -C demo gcovr
-
-gdb_demo: debug
- ${MAKE} -C demo gdb_demo
-
-install:
- ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0755 -d ${prefix}/include/libc3/window/sdl2
- ${LIBTOOL} --tag=CC --mode=install ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0644 ${HEADERS} ${prefix}/include/libc3/window/sdl2
- ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0755 -d ${prefix}/lib
- ${LIBTOOL} --tag=CC --mode=install ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0644 ${LIB} ${prefix}/lib
- ${LIBTOOL} --finish ${prefix}/lib
-
-lldb_demo: debug
- ${MAKE} -C demo lldb_demo
-
-test:
- ${MAKE} -C demo test
-
-update_sources:
- ./update_sources
-
-.PHONY: \
- all \
- asan \
- build \
- clean \
- cov \
- debug \
- demo \
- demo_asan \
- demo_cov \
- demo_debug \
- distclean \
- gdb_demo \
- install \
- lldb_demo \
- test \
- update_sources \
-
-include config.mk
-include sources.mk
diff --git a/libkc3_window/sdl2/configure b/libkc3_window/sdl2/configure
deleted file mode 100755
index c2d1d93..0000000
--- a/libkc3_window/sdl2/configure
+++ /dev/null
@@ -1,123 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-set -e
-
-echo "$PWD/configure"
-
-export SRC_TOP="$(dirname "$PWD")"
-
-. ../../config.subr
-
-LIB=libkc3_window_sdl2.la
-LIB_ASAN=libkc3_window_sdl2_asan.la
-LIB_COV=libkc3_window_sdl2_cov.la
-LIB_DEBUG=libkc3_window_sdl2_debug.la
-
-echo "LIB = $LIB" >> ${CONFIG_MK}
-echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
-echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
-echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
-
-. ./sources.sh
-
-OBJECTS="$(c2ext .main.lo "$SOURCES")"
-echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
-OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
-OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
-OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
-
-# Common config for all targets
-CPPFLAGS="-I../.. $CPPFLAGS"
-CFLAGS="$CFLAGS -W -Wall -Werror -std=c11 -pedantic -pipe"
-LDFLAGS="--shared ${LDFLAGS}"
-config_asan
-config_gnu
-config_i386
-pkg_config libbsd-overlay
-pkg_config libmd
-pkg_config freetype2
-pkg_config gl
-pkg_config glew
-pkg_config glu
-pkg_config glut
-pkg_config libffi
-pkg_config libpng
-config_lib OPENGL -framework OpenGL
-pkg_config sdl2
-config_define PREFIX "\"${PREFIX}\""
-LIBS="$LIBS -rpath ${PREFIX}/lib"
-
-# Address Sanitizer config
-CPPFLAGS_ASAN="$CPPFLAGS"
-CFLAGS_ASAN="$CFLAGS -DDEBUG -O1 -g"
-CFLAGS_ASAN="$CFLAGS_ASAN -fsanitize=address -fno-omit-frame-pointer"
-LDFLAGS_ASAN="$LDFLAGS"
-LIBS_LOCAL_ASAN="../libkc3_window_asan.la"
-LIBS_ASAN="$LIBS_LOCAL_ASAN $LIBS"
-
-# Coverage config
-CPPFLAGS_COV="$CPPFLAGS"
-CFLAGS_COV="$CFLAGS -DDEBUG --coverage"
-LDFLAGS_COV="$LDFLAGS"
-LIBS_LOCAL_COV="../libkc3_window_cov.la"
-LIBS_COV="$LIBS_LOCAL_COV $LIBS"
-
-# Debug config
-CPPFLAGS_DEBUG="$CPPFLAGS"
-CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
-LDFLAGS_DEBUG="$LDFLAGS"
-LIBS_LOCAL_DEBUG="../libkc3_window_debug.la"
-LIBS_DEBUG="$LIBS_LOCAL_DEBUG $LIBS"
-
-# Main config
-DEFAULT_CFLAGS="-O2 -fPIC"
-if [ "x$ENV_CFLAGS" = "x" ]; then
- CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
-fi
-CFLAGS="$CFLAGS -DNDEBUG"
-LIBS_LOCAL="../libkc3_window.la"
-LIBS="$LIBS_LOCAL $LIBS"
-
-echo "LIB = $LIB" >> ${CONFIG_MK}
-echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
-echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
-echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
-echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
-echo "LIBS = $LIBS" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
-echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
-echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
-echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
-echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
-echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
-
-update_build
-update_build_lib
-
-build_lo
-build_lib
-
-update_config_mk
-env_reset
-
-config_subdirs demo
diff --git a/libkc3_window/sdl2/demo/Makefile b/libkc3_window/sdl2/demo/Makefile
deleted file mode 100644
index c376721..0000000
--- a/libkc3_window/sdl2/demo/Makefile
+++ /dev/null
@@ -1,107 +0,0 @@
-## kc3
-## Copyright 2022-2024 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.
-
-CLEANFILES = *.a ${PROG} ${PROG_ASAN} ${PROG_COV} ${PROG_DEBUG} *.css \
- *.gcno *.html *.o .libs *.lo
-
-CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
-CLEANFILES += ${CLEANFILES_COV}
-
-DISTCLEANFILES = ${CLEANFILES} config.mk
-
-build:
- ${MAKE} ${PROG}
- if ${HAVE_DARWIN}; then ${MAKE} -C macos build; fi
-
-all:
- ${MAKE} build
- if ${HAVE_GCOV}; then ${MAKE} cov; fi
- ${MAKE} debug
- if ${HAVE_ASAN}; then ${MAKE} asan; fi
-
-asan:
- ${MAKE} ${PROG_ASAN}
- if ${HAVE_DARWIN}; then ${MAKE} -C macos asan; fi
-
-clean:
- rm -rf ${CLEANFILES}
- if ${HAVE_DARWIN}; then ${MAKE} -C macos clean; fi
-
-clean_cov:
- rm -rf ${CLEANFILES_COV}
- if ${HAVE_DARWIN}; then ${MAKE} -C macos clean_cov; fi
-
-cov:
- ${MAKE} ${PROG_COV}
- if ${HAVE_DARWIN}; then ${MAKE} -C macos cov; fi
-
-debug:
- ${MAKE} ${PROG_DEBUG}
- if ${HAVE_DARWIN}; then ${MAKE} -C macos debug; fi
-
-demo:
- ${MAKE} ${PROG}
- if ${HAVE_DARWIN}; then ${MAKE} -C macos demo; else time ./${PROG}; fi
-
-demo_asan:
- ${MAKE} asan
- if ${HAVE_DARWIN}; then ${MAKE} -C macos demo_asan; else time ./${PROG_ASAN}; fi
-
-demo_cov:
- ${MAKE} cov
- if ${HAVE_DARWIN}; then ${MAKE} -C macos demo_cov; else time ./${PROG_COV}; fi
-
-demo_debug:
- ${MAKE} debug
- if ${HAVE_DARWIN}; then ${MAKE} -C macos demo_debug; else time ./${PROG_DEBUG}; fi
-
-distclean:
- rm -rf ${DISTCLEANFILES}
- if ${HAVE_DARWIN}; then ${MAKE} -C macos distclean; fi
-
-gcovr:
- gcovr --gcov-executable ${GCOV} --html-details ${PROG}.html
- if ${HAVE_DARWIN}; then ${MAKE} -C macos gcovr; fi
-
-gdb_demo: debug
- if ${HAVE_DARWIN}; then ${MAKE} -C macos gdb_demo; else gdb .libs/${PROG_DEBUG}; fi
-
-install:
- install -m 755 -d ${prefix}/bin
- install -m 755 ${PROG} ${prefix}/bin/${PROG}
-
-lldb_demo: debug
- if ${HAVE_DARWIN}; then ${MAKE} -C macos lldb_demo; else lldb .libs/${PROG_DEBUG}; fi
-
-update_sources:
- ./update_sources
-
-.PHONY: \
- all \
- asan \
- build \
- clean \
- clean_cov \
- cov \
- debug \
- demo \
- demo_asan \
- demo_cov \
- demo_debug \
- distclean \
- gdb_demo \
- install \
- lldb_demo \
- update_sources \
-
-include config.mk
-include sources.mk
diff --git a/libkc3_window/sdl2/demo/bg_rect.c b/libkc3_window/sdl2/demo/bg_rect.c
deleted file mode 100644
index 89cd649..0000000
--- a/libkc3_window/sdl2/demo/bg_rect.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "../types.h"
-#include "bg_rect.h"
-
-bool bg_rect_load (s_sequence *seq)
-{
- (void) seq;
- return true;
-}
-
-bool bg_rect_render (s_sequence *seq)
-{
-#define BG_RECT_COLOR_MAX 8
- const s_rgb color[BG_RECT_COLOR_MAX] = {
- {0, 0, 0},
- {1, 0, 0},
- {1, 1, 0},
- {0, 1, 0},
- {0, 1, 1},
- {0, 0, 1},
- {1, 0, 1},
- {1, 1, 1}
- };
- u8 c1;
- u8 c2;
- double p;
- double q;
- s_rgb rgb;
- c1 = (u8) trunc(seq->t) % BG_RECT_COLOR_MAX;
- c2 = (u8) trunc(seq->t + 1.0) % BG_RECT_COLOR_MAX;
- p = fmod(seq->t, 1.0);
- q = 1.0 - p;
- rgb.r = color[c1].r * q + color[c2].r * p;
- rgb.g = color[c1].g * q + color[c2].g * p;
- rgb.b = color[c1].b * q + color[c2].b * p;
- assert(glGetError() == GL_NO_ERROR);
- glClearColor(rgb.r, rgb.g, rgb.b, 1.0);
- assert(glGetError() == GL_NO_ERROR);
- glClear(GL_COLOR_BUFFER_BIT);
- assert(glGetError() == GL_NO_ERROR);
- return true;
-}
-
-bool bg_rect_unload (s_sequence *seq)
-{
- (void) seq;
- return true;
-}
diff --git a/libkc3_window/sdl2/demo/bg_rect.h b/libkc3_window/sdl2/demo/bg_rect.h
deleted file mode 100644
index 144f39d..0000000
--- a/libkc3_window/sdl2/demo/bg_rect.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 BG_RECT_H
-#define BG_RECT_H
-
-#include "../types.h"
-
-bool bg_rect_load (s_sequence *seq);
-bool bg_rect_render (s_sequence *seq);
-bool bg_rect_unload (s_sequence *seq);
-
-#endif /* BG_RECT_H */
diff --git a/libkc3_window/sdl2/demo/configure b/libkc3_window/sdl2/demo/configure
deleted file mode 100755
index 490f1e9..0000000
--- a/libkc3_window/sdl2/demo/configure
+++ /dev/null
@@ -1,145 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-set -e
-
-echo "$PWD/configure"
-
-export SRC_TOP="$(dirname "$PWD")"
-
-. ../../../config.subr
-
-PROG=kc3_window_sdl2_demo
-PROG_ASAN=kc3_window_sdl2_demo_asan
-PROG_COV=kc3_window_sdl2_demo_cov
-PROG_DEBUG=kc3_window_sdl2_demo_debug
-
-echo "PROG = $PROG" >> ${CONFIG_MK}
-echo "PROG_ASAN = $PROG_ASAN" >> ${CONFIG_MK}
-echo "PROG_COV = $PROG_COV" >> ${CONFIG_MK}
-echo "PROG_DEBUG = $PROG_DEBUG" >> ${CONFIG_MK}
-
-. ./sources.sh
-
-OBJECTS="$(c2ext .main.lo "$SOURCES")"
-echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
-
-OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
-echo "OBJECTS_ASAN = $OBJECTS_ASAN" >> ${CONFIG_MK}
-
-if $HAVE_GCOV; then
- OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
- echo "OBJECTS_COV = $OBJECTS_COV" >> ${CONFIG_MK}
-fi
-
-OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
-echo "OBJECTS_DEBUG = $OBJECTS_DEBUG" >> ${CONFIG_MK}
-
-# Common config for all targets
-CPPFLAGS="-I../../.. $CPPFLAGS"
-CFLAGS="$CFLAGS -W -Wall -Werror -Wno-error=unknown-pragmas"
-CFLAGS="$CFLAGS -std=c11 -pedantic -pipe"
-LIBS="$LIBS -lm"
-config_asan
-config_gnu
-config_i386
-pkg_config libbsd-overlay
-pkg_config libmd
-pkg_config freetype2
-pkg_config gl
-pkg_config glew
-pkg_config glu
-pkg_config glut
-pkg_config libffi
-pkg_config libpng
-config_lib OPENGL -framework OpenGL
-config_lib OPENGL -lopengl32 -lglu32
-config_lib OPENMP -fopenmp
-config_define HAVE_OPENMP "${HAVE_OPENMP}"
-pkg_config sdl2
-
-# Asan config
-CPPFLAGS_ASAN="$CPPFLAGS"
-CFLAGS_ASAN="$CFLAGS -DDEBUG -O1 -g"
-CFLAGS_ASAN="$CFLAGS_ASAN -fsanitize=address -fno-omit-frame-pointer"
-LDFLAGS_ASAN="$LDFLAGS"
-LOCAL_LIBS_ASAN="../../../libkc3/libkc3_asan.la"
-LOCAL_LIBS_ASAN="$LOCAL_LIBS_ASAN ../../libkc3_window_asan.la"
-LOCAL_LIBS_ASAN="$LOCAL_LIBS_ASAN ../libkc3_window_sdl2_asan.la"
-LIBS_ASAN="$LOCAL_LIBS_ASAN $LIBS"
-
-# Coverage config
-CPPFLAGS_COV="$CPPFLAGS"
-CFLAGS_COV="$CFLAGS -DDEBUG -fprofile-arcs -ftest-coverage"
-LDFLAGS_COV="$LDFLAGS --coverage"
-LOCAL_LIBS_COV="../../../libkc3/libkc3_cov.la"
-LOCAL_LIBS_COV="$LOCAL_LIBS_COV ../../libkc3_window_cov.la"
-LOCAL_LIBS_COV="$LOCAL_LIBS_COV ../libkc3_window_sdl2_cov.la"
-LIBS_COV="$LOCAL_LIBS_COV $LIBS -lgcov"
-
-# Debug config
-CPPFLAGS_DEBUG="$CPPFLAGS"
-CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
-LDFLAGS_DEBUG="$LDFLAGS"
-LOCAL_LIBS_DEBUG="../../../libkc3/libkc3_debug.la"
-LOCAL_LIBS_DEBUG="$LOCAL_LIBS_DEBUG ../../libkc3_window_debug.la"
-LOCAL_LIBS_DEBUG="$LOCAL_LIBS_DEBUG ../libkc3_window_sdl2_debug.la"
-LIBS_DEBUG="$LOCAL_LIBS_DEBUG $LIBS"
-
-# Main config
-DEFAULT_CFLAGS="-O2 -fPIC"
-if [ "x$ENV_CFLAGS" = "x" ]; then
- CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
-fi
-CFLAGS="$CFLAGS -DNDEBUG"
-LOCAL_LIBS="../../../libkc3/libkc3.la"
-LOCAL_LIBS="$LOCAL_LIBS ../../libkc3_window.la"
-LOCAL_LIBS="$LOCAL_LIBS ../libkc3_window_sdl2.la"
-LIBS="$LOCAL_LIBS $LIBS"
-
-echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
-echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
-echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
-echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
-echo "LIBS = $LIBS" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
-echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
-echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
-echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
-echo >> ${CONFIG_MK}
-echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
-echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
-
-update_build
-update_build_prog
-
-build_lo
-build_prog
-
-if [ "x$(uname)" = "xDarwin" ]; then
- HAVE_DARWIN=true
-else
- HAVE_DARWIN=false
-fi
-echo "HAVE_DARWIN = $HAVE_DARWIN" >> ${CONFIG_MK}
-
-update_config_mk
-
-if ${HAVE_DARWIN}; then
- config_subdirs macos
-fi
diff --git a/libkc3_window/sdl2/demo/earth.c b/libkc3_window/sdl2/demo/earth.c
deleted file mode 100644
index 45952dc..0000000
--- a/libkc3_window/sdl2/demo/earth.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "../window_sdl2.h"
-#include "../gl_camera.h"
-#include "../mat4.h"
-#include "../gl_object.h"
-#include "../gl_sphere.h"
-#include "../gl_sprite.h"
-#include "earth.h"
-
-#define EARTH_CAMERA_ROTATION_Z_SPEED 0.1
-#define EARTH_SEGMENTS_U 200
-#define EARTH_SEGMENTS_V 100
-
-s_gl_sprite g_sprite_earth = {0};
-
-bool earth_load (s_sequence *seq)
-{
- s_map *map;
- s_mat4 matrix;
- s_gl_camera *camera;
- s_gl_sphere *sphere;
- const f32 sphere_radius = 5.0;
- s_window_sdl2 *window;
- assert(seq);
- window = seq->window;
- assert(window);
- camera = gl_camera_new(window->w, window->h);
- if (! camera)
- return false;
- sphere = gl_sphere_new(EARTH_SEGMENTS_U, EARTH_SEGMENTS_V);
- if (! sphere)
- return false;
- mat4_init_scale(&matrix, sphere_radius, sphere_radius,
- sphere_radius);
- gl_object_transform(&sphere->object, &matrix);
- gl_object_update(&sphere->object);
- if (! tag_map(&seq->tag, 3))
- return false;
- map = &seq->tag.data.map;
- tag_init_sym( map->key + 0, sym_1("camera"));
- tag_init_ptr_free( map->value + 0, camera);
- tag_init_sym( map->key + 1, sym_1("camera_rot_x_speed"));
- tag_init_f64( map->value + 1, 0.01);
- tag_init_sym( map->key + 2, sym_1("sphere"));
- tag_init_struct_with_data(map->value + 2, sym_1("GL.Sphere"),
- sphere, false);
- return true;
-}
-
-bool earth_render (s_sequence *seq)
-{
- s_gl_camera *camera;
- f64 *camera_rot_x_speed;
- s_map *map;
- s_gl_sphere *sphere;
- s_window_sdl2 *window;
- assert(seq);
- window = seq->window;
- assert(window);
- if (! seq || seq->tag.type != TAG_MAP ||
- seq->tag.data.map.count != 3) {
- err_puts("earth_render: invalid seq->tag");
- return false;
- }
- map = &seq->tag.data.map;
- if (map->value[0].type != TAG_PTR_FREE ||
- map->value[1].type != TAG_F64 ||
- map->value[2].type != TAG_STRUCT) {
- err_puts("earth_render: invalid map");
- return false;
- }
- camera = map->value[0].data.ptr_free.p;
- camera_rot_x_speed = &map->value[1].data.f64;
- sphere = map->value[2].data.struct_.data;
- gl_camera_set_aspect_ratio(camera, window->w, window->h);
- camera->rotation.x += seq->dt * (*camera_rot_x_speed) *
- M_PI * 2.0f;
- if (camera->rotation.x > M_PI || camera->rotation.x < 0)
- *camera_rot_x_speed *= -1.0;
- camera->rotation.z += seq->dt * EARTH_CAMERA_ROTATION_Z_SPEED *
- M_PI * 2.0f;
- assert(glGetError() == GL_NO_ERROR);
- gl_camera_render(camera);
- assert(glGetError() == GL_NO_ERROR);
- glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
- assert(glGetError() == GL_NO_ERROR);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- assert(glGetError() == GL_NO_ERROR);
- assert(glGetError() == GL_NO_ERROR);
- assert(glGetError() == GL_NO_ERROR);
- assert(glGetError() == GL_NO_ERROR);
- glEnable(GL_DEPTH_TEST);
- assert(glGetError() == GL_NO_ERROR);
- gl_camera_bind_texture(camera,
- gl_sprite_texture(&g_sprite_earth, 0));
- assert(glGetError() == GL_NO_ERROR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
- GL_LINEAR_MIPMAP_LINEAR);
- assert(glGetError() == GL_NO_ERROR);
- gl_sphere_render(sphere);
- glDisable(GL_DEPTH_TEST);
- return true;
-}
-
-bool earth_unload (s_sequence *seq)
-{
- (void) seq;
- return true;
-}
diff --git a/libkc3_window/sdl2/demo/earth.h b/libkc3_window/sdl2/demo/earth.h
deleted file mode 100644
index 316618c..0000000
--- a/libkc3_window/sdl2/demo/earth.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 EARTH_H
-#define EARTH_H
-
-#include "../types.h"
-#include "window_sdl2_demo.h"
-
-extern s_gl_sprite g_sprite_earth;
-extern s_gl_sprite g_sprite_earth_night;
-
-bool earth_load (s_sequence *seq);
-bool earth_render (s_sequence *seq);
-bool earth_unload (s_sequence *seq);
-
-#endif /* EARTH_H */
diff --git a/libkc3_window/sdl2/demo/flies.c b/libkc3_window/sdl2/demo/flies.c
deleted file mode 100644
index 74249cc..0000000
--- a/libkc3_window/sdl2/demo/flies.c
+++ /dev/null
@@ -1,360 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "../gl_font.h"
-#include "../mat4.h"
-#include "../gl_ortho.h"
-#include "../gl_text.h"
-#include "../gl_sprite.h"
-#include "../window_sdl2.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_gl_font g_font_flies = {0};
-s_gl_sprite g_sprite_dead_fly = {0};
-s_gl_sprite g_sprite_fly = {0};
-s_gl_text g_text_flies_in = {0};
-s_gl_text g_text_flies_out = {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->value[0].data.array;
- in = &map->value[1].data.uw;
- t = &map->value[3].data.f64;
- array_data_set(board, address, &g_board_item_fly);
- *t = 0.0;
- (*in)++;
-}
-
-bool flies_load (s_sequence *seq)
-{
- uw address[2];
- s_array *board;
- uw i;
- uw j;
- s_map *map;
- tag_map(&seq->tag, 4);
- map = &seq->tag.data.map;
- tag_init_sym( map->key + 0, sym_1("board"));
- tag_init_array(map->value + 0, sym_1("U8[]"),
- 2, (uw[]) {BOARD_SIZE, BOARD_SIZE});
- tag_init_sym( map->key + 1, sym_1("in"));
- tag_init_uw( map->value + 1, 0);
- tag_init_sym( map->key + 2, sym_1("out"));
- tag_init_uw( map->value + 2, 0);
- tag_init_sym( map->key + 3, sym_1("t"));
- tag_init_uw( map->value + 3, 0);
- board = &map->value[0].data.array;
- array_allocate(board);
- 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);
- if (! gl_text_init_1(&g_text_flies_in, &g_font_flies, "In 0"))
- return false;
- gl_text_update(&g_text_flies_in);
- if (! gl_text_init_1(&g_text_flies_out, &g_font_flies, "Out 0"))
- return false;
- gl_text_update(&g_text_flies_out);
- return true;
-}
-
-bool flies_render (s_sequence *seq)
-{
- char 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;
- s_mat4 matrix;
- s_mat4 matrix_1;
- s_mat4 matrix_2;
- uw r;
- uw random_bits = 0;
- f64 x;
- f64 y;
- s_window_sdl2 *window;
- assert(seq);
- window = seq->window;
- assert(window);
- glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT);
- /* io_inspect(&seq->tag); */
- if (!seq || seq->tag.type != TAG_MAP)
- return false;
- map = &seq->tag.data.map;
- if (map->count != 4 ||
- map->value[0].type != TAG_ARRAY ||
- map->value[1].type != TAG_UW ||
- map->value[2].type != TAG_UW ||
- map->value[3].type != TAG_UW)
- return false;
- board = &map->value[0].data.array;
- fly_in = &map->value[1].data.uw;
- fly_out = &map->value[2].data.uw;
- fly_time = &map->value[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_sprite_fly.pt_w;
- dead_fly_scale = 2.0 * board_item_w / g_sprite_dead_fly.pt_w;
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
- GL_LINEAR_MIPMAP_LINEAR);
- mat4_init_identity(&g_ortho.model_matrix);
- mat4_translate(&g_ortho.model_matrix, board_x, 60.0, 0.0);
- gl_ortho_update_model_matrix(&g_ortho);
- gl_ortho_color(&g_ortho, 1.0f, 1.0f, 1.0f, 1.0f);
- buf_init(&buf, false, sizeof(a), a);
- buf_write_1(&buf, "In ");
- buf_inspect_uw(&buf, fly_in);
- buf_write_u8(&buf, 0);
- gl_font_set_size(&g_font_flies, board_item_h);
- gl_text_update_1(&g_text_flies_in, a);
- gl_ortho_text_render(&g_ortho, &g_text_flies_in);
- buf_init(&buf, false, sizeof(a), a);
- buf_write_1(&buf, "Out ");
- buf_inspect_uw(&buf, fly_out);
- buf_write_u8(&buf, 0);
- gl_text_update_1(&g_text_flies_out, a);
- matrix = g_ortho.model_matrix; {
- x = board_item_w * (BOARD_SIZE / 2 + 1);
- mat4_translate(&g_ortho.model_matrix, x, 0.0, 0.0);
- gl_ortho_update_model_matrix(&g_ortho);
- gl_ortho_text_render(&g_ortho, &g_text_flies_out);
- g_ortho.model_matrix = matrix;
- mat4_translate(&g_ortho.model_matrix, 0.0, board_item_h, 0.0);
- gl_ortho_color(&g_ortho, 0.6f, 0.7f, 0.9f, 1.0f);
- gl_ortho_rect(&g_ortho, 0, 0, board_w, board_h);
- gl_ortho_color(&g_ortho, 1.0f, 1.0f, 1.0f, 1.0f);
- 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];
- matrix_1 = g_ortho.model_matrix; {
- mat4_translate(&g_ortho.model_matrix, 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:
- gl_ortho_bind_texture(&g_ortho, 0);
- gl_ortho_color(&g_ortho, 0.0f, 0.0f, 1.0f, 1.0f);
- gl_ortho_rect(&g_ortho, 0, 0, board_item_w + 1.0, board_item_h + 1.0);
- gl_ortho_color(&g_ortho, 1.0f, 1.0f, 1.0f, 1.0f);
- break;
- case BOARD_ITEM_FLY:
- matrix_2 = g_ortho.model_matrix; {
- mat4_translate(&g_ortho.model_matrix,
- -board_item_w / 2.0,
- -board_item_h / 2.0, 0.0);
- mat4_scale(&g_ortho.model_matrix, fly_scale,
- fly_scale, 1.0);
- gl_ortho_update_model_matrix(&g_ortho);
- gl_ortho_bind_texture(&g_ortho,
- gl_sprite_texture(&g_sprite_fly, 0));
- gl_ortho_color(&g_ortho, 1.0f, 1.0f, 1.0f, 1.0f);
- gl_ortho_rect(&g_ortho, 0, 0, g_sprite_fly.pt_w,
- g_sprite_fly.pt_h);
- gl_ortho_bind_texture(&g_ortho, 0);
- } g_ortho.model_matrix = matrix_2;
- 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 = arc4random();
- random_bits = 32;
- }
- 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:
- matrix_2 = g_ortho.model_matrix; {
- mat4_translate(&g_ortho.model_matrix,
- -board_item_w / 2.0,
- -board_item_h / 2.0, 0.0);
- mat4_scale(&g_ortho.model_matrix, dead_fly_scale,
- dead_fly_scale, 1.0);
- gl_ortho_update_model_matrix(&g_ortho);
- gl_ortho_bind_texture(&g_ortho,
- gl_sprite_texture(&g_sprite_dead_fly, 0));
- gl_ortho_color(&g_ortho, 1.0f, 1.0f, 1.0f, 1.0f);
- gl_ortho_rect(&g_ortho, 0, 0, g_sprite_dead_fly.pt_w,
- g_sprite_dead_fly.pt_h);
- gl_ortho_bind_texture(&g_ortho, 0);
- } g_ortho.model_matrix = matrix_2;
- break;
- }
- } g_ortho.model_matrix = matrix_1;
- address[0]++;
- }
- address[1]++;
- }
- } g_ortho.model_matrix = matrix;
- return true;
-}
-
-bool flies_unload (s_sequence *seq)
-{
- (void) seq;
- gl_text_clean(&g_text_flies_in);
- gl_text_clean(&g_text_flies_out);
- return true;
-}
diff --git a/libkc3_window/sdl2/demo/flies.h b/libkc3_window/sdl2/demo/flies.h
deleted file mode 100644
index b6ac102..0000000
--- a/libkc3_window/sdl2/demo/flies.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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_gl_font g_font_flies;
-extern s_gl_sprite g_sprite_dead_fly;
-extern s_gl_sprite g_sprite_fly;
-
-bool flies_load (s_sequence *seq);
-bool flies_render (s_sequence *seq);
-bool flies_unload (s_sequence *seq);
-
-#endif /* FLIES_H */
diff --git a/libkc3_window/sdl2/demo/lightspeed.c b/libkc3_window/sdl2/demo/lightspeed.c
deleted file mode 100644
index 7a50ca0..0000000
--- a/libkc3_window/sdl2/demo/lightspeed.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "../gl_lines.h"
-#include "../mat4.h"
-#include "../gl_ortho.h"
-#include "../vec3.h"
-#include "window_sdl2_demo.h"
-#include "lightspeed.h"
-
-s_gl_lines g_lines_stars = {0};
-s_gl_ortho g_ortho_lightspeed = {0};
-
-static void star_init (s_tag *star)
-{
- f64 x;
- f64 y;
- f64_random(&x);
- f64_random(&y);
- if (star->type != TAG_MAP || star->data.map.count != 3) {
- tag_map(star, 3);
- tag_init_sym(star->data.map.key + 0, sym_1("speed"));
- tag_init_sym(star->data.map.key + 1, sym_1("x"));
- tag_init_sym(star->data.map.key + 2, sym_1("y"));
- }
- tag_init_f64(star->data.map.value + 0, 0.0);
- tag_init_f64(star->data.map.value + 1, 2.0 * x - 1.0);
- tag_init_f64(star->data.map.value + 2, 2.0 * y - 1.0);
-}
-
-static void star_render (s_tag *star, s_sequence *seq, s_gl_vertex *v)
-{
- f64 q;
- f64 *speed;
- f64 *x;
- f64 *y;
- if (star->type != TAG_MAP || star->data.map.count < 3)
- star_init(star);
- speed = &star->data.map.value[0].data.f64;
- x = &star->data.map.value[1].data.f64;
- y = &star->data.map.value[2].data.f64;
- v[0].pos_x = *x;
- v[0].pos_y = *y;
- v[0].pos_z = 0.0;
- q = (1 + *speed / 20);
- v[1].pos_x = *x * q;
- v[1].pos_y = *y * q;
- v[1].pos_z = 0.0;
- q = (1 + *speed / 100);
- *x = *x * q;
- *y = *y * q;
- *speed += seq->dt;
- if ((*x == 0.0 && *y == 0.0) ||
- *x < -1.0 || *x > 1.0 ||
- *y < -1.0 || *y > 1.0)
- star_init(star);
-}
-
-bool lightspeed_load (s_sequence *seq)
-{
- uw i;
- uw star_count;
- s_window_sdl2 *window;
- assert(seq);
- window = seq->window;
- assert(window);
- tag_tuple(&seq->tag, LIGHTSPEED_STAR_MAX);
- star_count = window->w * window->h * LIGHTSPEED_STAR_PROBABILITY;
- if (star_count > LIGHTSPEED_STAR_MAX)
- star_count = LIGHTSPEED_STAR_MAX;
- i = 0;
- while (i < star_count) {
- star_init(seq->tag.data.tuple.tag + i);
- i++;
- }
- return true;
-}
-
-bool lightspeed_render (s_sequence *seq)
-{
- uw i;
- uw star_count;
- s_gl_vertex *v;
- s_window_sdl2 *window;
- assert(seq);
- window = seq->window;
- assert(window);
- mat4_init_identity(&g_ortho.model_matrix);
- mat4_scale(&g_ortho.model_matrix, (f32) window->w / 2.0f,
- (f32) window->h / 2.0f, 1.0f);
- mat4_translate(&g_ortho.model_matrix, 1, 1, 0);
- gl_ortho_update_model_matrix(&g_ortho);
- star_count = window->w * window->h * LIGHTSPEED_STAR_PROBABILITY;
- if (star_count > LIGHTSPEED_STAR_MAX)
- star_count = LIGHTSPEED_STAR_MAX;
- v = g_lines_stars.vertex.data;
- i = 0;
- while (i < star_count) {
- star_render(seq->tag.data.tuple.tag + i, seq, v);
- v += 2;
- i++;
- }
- assert(glGetError() == GL_NO_ERROR);
- gl_lines_update(&g_lines_stars, star_count);
- assert(glGetError() == GL_NO_ERROR);
- glDisable(GL_DEPTH_TEST);
- assert(glGetError() == GL_NO_ERROR);
- glClearColor(0, 0, 0, 1);
- assert(glGetError() == GL_NO_ERROR);
- glClear(GL_COLOR_BUFFER_BIT);
- assert(glGetError() == GL_NO_ERROR);
- glBlendColor(1, 1, 1, 0.7f);
- assert(glGetError() == GL_NO_ERROR);
- glEnable(GL_BLEND);
- assert(glGetError() == GL_NO_ERROR);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- assert(glGetError() == GL_NO_ERROR);
- glEnable(GL_LINE_SMOOTH);
- assert(glGetError() == GL_NO_ERROR);
- gl_lines_render(&g_lines_stars, star_count);
- assert(glGetError() == GL_NO_ERROR);
- return true;
-}
-
-bool lightspeed_unload (s_sequence *seq)
-{
- (void) seq;
- return true;
-}
diff --git a/libkc3_window/sdl2/demo/lightspeed.h b/libkc3_window/sdl2/demo/lightspeed.h
deleted file mode 100644
index 4c3889f..0000000
--- a/libkc3_window/sdl2/demo/lightspeed.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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_STAR_MAX (1024 * 1024)
-#define LIGHTSPEED_STAR_PROBABILITY 0.005
-
-extern s_gl_lines g_lines_stars;
-
-bool lightspeed_load (s_sequence *seq);
-bool lightspeed_render (s_sequence *seq);
-bool lightspeed_unload (s_sequence *seq);
-
-#endif /* LIGHTSPEED_H */
diff --git a/libkc3_window/sdl2/demo/macos/Makefile b/libkc3_window/sdl2/demo/macos/Makefile
deleted file mode 100644
index 0b59f80..0000000
--- a/libkc3_window/sdl2/demo/macos/Makefile
+++ /dev/null
@@ -1,109 +0,0 @@
-## kc3
-## Copyright 2022-2024 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.
-
-CLEANFILES = *.a ${APP_PROG} ${APP_PROG_ASAN} ${APP_PROG_COV} \
- ${APP_PROG_DEBUG} ${PROG} ${PROG_ASAN} ${PROG_COV} ${PROG_DEBUG} \
- *.css *.gcno *.html *.o .libs *.lo
-
-CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
-CLEANFILES += ${CLEANFILES_COV}
-
-DISTCLEANFILES = ${CLEANFILES} config.mk
-
-IMG_SOURCES = \
- ../../../../img/earth.png \
- ../../../../img/flaps.256.png \
- ../../../../img/flaps.png \
- ../../../../img/fly-dead.png \
- ../../../../img/fly-noto.png \
- ../../../../img/matrix_shade.png \
- ../../../../img/toast.128.png \
- ../../../../img/toast.png \
-
-FONT_SOURCES = \
- ../../../../fonts/Courier\ New \
- ../../../../fonts/NotoSans-Regular.ttf \
-
-build:
- ${MAKE} ${APP_PROG}
- ${MAKE} ${APP}/Contents/Frameworks
- rsync -aP --delete ../../../../lib ${APP}/Contents/
- rsync -aP ${IMG_SOURCES} ${APP}/Contents/img/
- rsync -aP ${FONT_SOURCES} ${APP}/Contents/fonts/
-
-all:
- ${MAKE} build
- if ${HAVE_GCOV}; then ${MAKE} cov; fi
- ${MAKE} debug
- if ${HAVE_ASAN}; then ${MAKE} asan; fi
-
-asan:
- ${MAKE} ${APP_PROG_ASAN}
- ${MAKE} ${APP_ASAN}/Contents/Frameworks
- rsync -aP --delete ../../../../lib ${APP_ASAN}/Contents/
- rsync -aP ${IMG_SOURCES} ${APP_ASAN}/Contents/img/
- rsync -aP ${FONT_SOURCES} ${APP_ASAN}/Contents/fonts/
-
-clean:
- rm -rf ${CLEANFILES}
-
-clean_cov:
- rm -rf ${CLEANFILES_COV}
-
-cov:
- ${MAKE} ${APP_PROG_COV}
- ${MAKE} ${APP_COV}/Contents/Frameworks
- rsync -aP --delete ../../../../lib ${APP_COV}/Contents/
- rsync -aP ${IMG_SOURCES} ${APP_COV}/Contents/img/
- rsync -aP ${FONT_SOURCES} ${APP_COV}/Contents/fonts/
-
-debug:
- ${MAKE} ${APP_PROG_DEBUG}
- ${MAKE} ${APP_DEBUG}/Contents/Frameworks
- rsync -aP --delete ../../../../lib ${APP_DEBUG}/Contents/
- rsync -aP ${IMG_SOURCES} ${APP_DEBUG}/Contents/img/
- rsync -aP ${FONT_SOURCES} ${APP_DEBUG}/Contents/fonts/
-
-demo: build
- time ${APP_PROG}
-
-demo_debug: debug
- time ${APP_PROG_DEBUG}
-
-distclean:
- rm -rf ${DISTCLEANFILES}
-
-gcovr:
- gcovr --gcov-executable ${GCOV} --html-details ${PROG}.html
-
-gdb_demo: debug
- if [ -f ${PROG_DEBUG}.core ]; then gdb .libs/${PROG_DEBUG} ${PROG_DEBUG}.core; else gdb .libs/${PROG_DEBUG}; fi
-
-lldb_demo: debug
- lldb ${APP_PROG_DEBUG}
-
-install:
- install -m 755 -d ${prefix}/bin
- install -m 755 ${PROG} ${prefix}/bin/${PROG}
-
-.PHONY: \
- all \
- asan \
- clean \
- clean_cov \
- cov \
- debug \
- demo \
- distclean \
- gdb_demo
-
-include config.mk
diff --git a/libkc3_window/sdl2/demo/macos/c3_window_sdl2_demo.app/Contents/Info.plist b/libkc3_window/sdl2/demo/macos/c3_window_sdl2_demo.app/Contents/Info.plist
deleted file mode 100644
index 16d4085..0000000
--- a/libkc3_window/sdl2/demo/macos/c3_window_sdl2_demo.app/Contents/Info.plist
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleExecutable</key>
- <string>c3_window_sdl2_demo</string>
- <key>CFBundleIconFile</key>
- <string>c3</string>
- <key>CFBundleIdentifier</key>
- <string>io.kmx.c3-window-sdl2-demo</string>
- <key>NSHighResolutionCapable</key>
- <true/>
-</dict>
-</plist>
diff --git a/libkc3_window/sdl2/demo/macos/c3_window_sdl2_demo.app/Contents/Resources/c3.icns b/libkc3_window/sdl2/demo/macos/c3_window_sdl2_demo.app/Contents/Resources/c3.icns
deleted file mode 100644
index 377277a..0000000
Binary files a/libkc3_window/sdl2/demo/macos/c3_window_sdl2_demo.app/Contents/Resources/c3.icns and /dev/null differ
diff --git a/libkc3_window/sdl2/demo/macos/c3_window_sdl2_demo_debug.app/Contents/Info.plist b/libkc3_window/sdl2/demo/macos/c3_window_sdl2_demo_debug.app/Contents/Info.plist
deleted file mode 100644
index 3e35f4c..0000000
--- a/libkc3_window/sdl2/demo/macos/c3_window_sdl2_demo_debug.app/Contents/Info.plist
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleExecutable</key>
- <string>c3_window_sdl2_demo_debug</string>
- <key>CFBundleIconFile</key>
- <string>c3</string>
- <key>CFBundleIdentifier</key>
- <string>io.kmx.c3-window-sdl2-demo</string>
- <key>NSHighResolutionCapable</key>
- <true/>
-</dict>
-</plist>
diff --git a/libkc3_window/sdl2/demo/macos/c3_window_sdl2_demo_debug.app/Contents/Resources/c3.icns b/libkc3_window/sdl2/demo/macos/c3_window_sdl2_demo_debug.app/Contents/Resources/c3.icns
deleted file mode 100644
index 377277a..0000000
Binary files a/libkc3_window/sdl2/demo/macos/c3_window_sdl2_demo_debug.app/Contents/Resources/c3.icns and /dev/null differ
diff --git a/libkc3_window/sdl2/demo/macos/configure b/libkc3_window/sdl2/demo/macos/configure
deleted file mode 100755
index 0e1e486..0000000
--- a/libkc3_window/sdl2/demo/macos/configure
+++ /dev/null
@@ -1,132 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-set -e
-
-export SRC_TOP="$(dirname "$PWD")"
-
-. ../../../../config.subr
-
-PROG=c3_window_sdl2_demo
-PROG_ASAN=c3_window_sdl2_demo_asan
-PROG_COV=c3_window_sdl2_demo_cov
-PROG_DEBUG=c3_window_sdl2_demo_debug
-
-echo "PROG = $PROG" >> ${CONFIG_MK}
-echo "PROG_ASAN = $PROG_ASAN" >> ${CONFIG_MK}
-echo "PROG_COV = $PROG_COV" >> ${CONFIG_MK}
-echo "PROG_DEBUG = $PROG_DEBUG" >> ${CONFIG_MK}
-
-APP=c3_window_sdl2_demo.app
-APP_ASAN=c3_window_sdl2_demo_asan.app
-APP_COV=c3_window_sdl2_demo_cov.app
-APP_DEBUG=c3_window_sdl2_demo_debug.app
-
-echo "APP = $APP" >> ${CONFIG_MK}
-echo "APP_ASAN = ${APP_ASAN}" >> ${CONFIG_MK}
-echo "APP_COV = ${APP_COV}" >> ${CONFIG_MK}
-echo "APP_DEBUG = ${APP_DEBUG}" >> ${CONFIG_MK}
-
-APP_PROG=${APP}/Contents/MacOS/${PROG}
-APP_PROG_ASAN=${APP_ASAN}/Contents/MacOS/${PROG_ASAN}
-APP_PROG_COV=${APP_COV}/Contents/MacOS/${PROG_COV}
-APP_PROG_DEBUG=${APP_DEBUG}/Contents/MacOS/${PROG_DEBUG}
-
-echo "APP_PROG = $APP_PROG" >> ${CONFIG_MK}
-echo "APP_PROG_ASAN = $APP_PROG_ASAN" >> ${CONFIG_MK}
-echo "APP_PROG_COV = $APP_PROG_COV" >> ${CONFIG_MK}
-echo "APP_PROG_DEBUG = $APP_PROG_DEBUG" >> ${CONFIG_MK}
-
-echo >> ${CONFIG_MK}
-echo "${APP_PROG}: ../.libs/${PROG}" >> ${CONFIG_MK}
-echo " mkdir -p ${APP}/Contents/MacOS" >> ${CONFIG_MK}
-echo " cp ../.libs/${PROG} ${APP_PROG}" >> ${CONFIG_MK}
-
-BUNDLE_LIBS_COMMON="/usr/local/lib/libSDL2-2.0.0.dylib"
-
-BUNDLE_LIBS="${BUNDLE_LIBS_COMMON} ../../../../libkc3/.libs/libkc3.0.dylib ../../../.libs/libkc3_window.0.dylib ../../.libs/libkc3_window_sdl2.0.dylib"
-echo >> ${CONFIG_MK}
-echo "${APP}/Contents/Frameworks: ${BUNDLE_LIBS}" >> ${CONFIG_MK}
-echo " mkdir -p ${APP}/Contents/Frameworks" >> ${CONFIG_MK}
-echo " cp ${BUNDLE_LIBS} ${APP}/Contents/Frameworks/" >> ${CONFIG_MK}
-for BUNDLE_LIB in ${BUNDLE_LIBS}; do
- L=$(basename $BUNDLE_LIB)
- echo " install_name_tool -id @executable_path/../Frameworks/ ${APP}/Contents/Frameworks/$L" >> ${CONFIG_MK}
- echo " install_name_tool -change ${LIBDIR}/$L @executable_path/../Frameworks/$L ${APP}/Contents/MacOS/${PROG}" >> ${CONFIG_MK}
- echo " DEPS=\$\$(otool -L '${BUNDLE_LIB}' | awk '/^\t.+(\/usr\/lib|\/System)/ { next } /^\t/ { print \$\$1 }'); for DEP in \$\${DEPS}; do D=\$\$(basename \"\$\${DEP}\"); if [ -f ${APP}/Contents/Frameworks/\$\$D ]; then install_name_tool -change \$\${DEP} @executable_path/../Frameworks/\$\$D ${APP}/Contents/Frameworks/$L; fi; done" >> ${CONFIG_MK}
-done
-echo >> ${CONFIG_MK}
-echo ".PHONY: \\" >> ${CONFIG_MK}
-echo " ${APP}/Contents/Frameworks" >> ${CONFIG_MK}
-
-echo >> ${CONFIG_MK}
-echo "${APP_PROG_ASAN}: ../.libs/${PROG_ASAN}" >> ${CONFIG_MK}
-echo " mkdir -p ${APP_ASAN}/Contents/MacOS" >> ${CONFIG_MK}
-echo " cp ../.libs/${PROG_ASAN} ${APP_PROG_ASAN}" >> ${CONFIG_MK}
-
-BUNDLE_LIBS_ASAN="${BUNDLE_LIBS_COMMON} ../../../../libkc3/.libs/libkc3_asan.0.dylib ../../../.libs/libkc3_window_asan.0.dylib ../../.libs/libkc3_window_sdl2_asan.0.dylib"
-echo >> ${CONFIG_MK}
-echo "${APP_ASAN}/Contents/Frameworks: ${BUNDLE_LIBS_ASAN}" >> ${CONFIG_MK}
-echo " mkdir -p ${APP_ASAN}/Contents/Frameworks" >> ${CONFIG_MK}
-echo " cp ${BUNDLE_LIBS_ASAN} ${APP_ASAN}/Contents/Frameworks/" >> ${CONFIG_MK}
-for BUNDLE_LIB in ${BUNDLE_LIBS_ASAN}; do
- L=$(basename $BUNDLE_LIB)
- echo " install_name_tool -id @executable_path/../Frameworks/ ${APP_ASAN}/Contents/Frameworks/$L" >> ${CONFIG_MK}
- echo " install_name_tool -change ${LIBDIR}/$L @executable_path/../Frameworks/$L ${APP_ASAN}/Contents/MacOS/${PROG_ASAN}" >> ${CONFIG_MK}
- echo " DEPS=\$\$(otool -L '${BUNDLE_LIB}' | awk '/^\t.+(\/usr\/lib|\/System)/ { next } /^\t/ { print \$\$1 }'); for DEP in \$\${DEPS}; do D=\$\$(basename \"\$\${DEP}\"); if [ -f ${APP_ASAN}/Contents/Frameworks/\$\$D ]; then install_name_tool -change \$\${DEP} @executable_path/../Frameworks/\$\$D ${APP_ASAN}/Contents/Frameworks/$L; fi; done" >> ${CONFIG_MK}
-done
-echo >> ${CONFIG_MK}
-echo ".PHONY: \\" >> ${CONFIG_MK}
-echo " ${APP_ASAN}/Contents/Frameworks" >> ${CONFIG_MK}
-
-echo >> ${CONFIG_MK}
-echo "${APP_PROG_COV}: ../.libs/${PROG_COV}" >> ${CONFIG_MK}
-echo " mkdir -p ${APP_COV}/Contents/MacOS" >> ${CONFIG_MK}
-echo " cp ../.libs/${PROG_COV} ${APP_PROG_COV}" >> ${CONFIG_MK}
-
-BUNDLE_LIBS_COV="${BUNDLE_LIBS_COMMON} ../../../../libkc3/.libs/libkc3_cov.0.dylib ../../../.libs/libkc3_window_cov.0.dylib ../../.libs/libkc3_window_sdl2_cov.0.dylib"
-echo >> ${CONFIG_MK}
-echo "${APP_COV}/Contents/Frameworks: ${BUNDLE_LIBS_COV}" >> ${CONFIG_MK}
-echo " mkdir -p ${APP_COV}/Contents/Frameworks" >> ${CONFIG_MK}
-echo " cp ${BUNDLE_LIBS_COV} ${APP_COV}/Contents/Frameworks/" >> ${CONFIG_MK}
-for BUNDLE_LIB in ${BUNDLE_LIBS_COV}; do
- L=$(basename $BUNDLE_LIB)
- echo " install_name_tool -id @executable_path/../Frameworks/ ${APP_COV}/Contents/Frameworks/$L" >> ${CONFIG_MK}
- echo " install_name_tool -change ${LIBDIR}/$L @executable_path/../Frameworks/$L ${APP_COV}/Contents/MacOS/${PROG}" >> ${CONFIG_MK}
- echo " DEPS=\$\$(otool -L '${BUNDLE_LIB}' | awk '/^\t.+(\/usr\/lib|\/System)/ { next } /^\t/ { print \$\$1 }'); for DEP in \$\${DEPS}; do D=\$\$(basename \"\$\${DEP}\"); if [ -f ${APP_COV}/Contents/Frameworks/\$\$D ]; then install_name_tool -change \$\${DEP} @executable_path/../Frameworks/\$\$D ${APP_COV}/Contents/Frameworks/$L; fi; done" >> ${CONFIG_MK}
-done
-echo >> ${CONFIG_MK}
-echo ".PHONY: \\" >> ${CONFIG_MK}
-echo " ${APP_COV}/Contents/Frameworks" >> ${CONFIG_MK}
-
-echo >> ${CONFIG_MK}
-echo "${APP_PROG_DEBUG}: ../.libs/${PROG_DEBUG}" >> ${CONFIG_MK}
-echo " mkdir -p ${APP_DEBUG}/Contents/MacOS" >> ${CONFIG_MK}
-echo " cp ../.libs/${PROG_DEBUG} ${APP_PROG_DEBUG}" >> ${CONFIG_MK}
-
-BUNDLE_LIBS_DEBUG="${BUNDLE_LIBS_COMMON} ../../../../libkc3/.libs/libkc3_debug.0.dylib ../../../.libs/libkc3_window_debug.0.dylib ../../.libs/libkc3_window_sdl2_debug.0.dylib"
-echo >> ${CONFIG_MK}
-echo "${APP_DEBUG}/Contents/Frameworks: ${BUNDLE_LIBS_DEBUG}" >> ${CONFIG_MK}
-echo " mkdir -p ${APP_DEBUG}/Contents/Frameworks" >> ${CONFIG_MK}
-echo " cp ${BUNDLE_LIBS_DEBUG} ${APP_DEBUG}/Contents/Frameworks/" >> ${CONFIG_MK}
-for BUNDLE_LIB in ${BUNDLE_LIBS_DEBUG}; do
- L=$(basename $BUNDLE_LIB)
- echo " install_name_tool -id @executable_path/../Frameworks/ ${APP_DEBUG}/Contents/Frameworks/$L" >> ${CONFIG_MK}
- echo " install_name_tool -change ${LIBDIR}/$L @executable_path/../Frameworks/$L ${APP_DEBUG}/Contents/MacOS/${PROG_DEBUG}" >> ${CONFIG_MK}
- echo " DEPS=\$\$(otool -L '${BUNDLE_LIB}' | awk '/^\t.+(\/usr\/lib|\/System)/ { next } /^\t/ { print \$\$1 }'); for DEP in \$\${DEPS}; do D=\$\$(basename \"\$\${DEP}\"); if [ -f ${APP_DEBUG}/Contents/Frameworks/\$\$D ]; then install_name_tool -change \$\${DEP} @executable_path/../Frameworks/\$\$D ${APP_DEBUG}/Contents/Frameworks/$L; fi; done" >> ${CONFIG_MK}
-done
-echo >> ${CONFIG_MK}
-echo ".PHONY: \\" >> ${CONFIG_MK}
-echo " ${APP_DEBUG}/Contents/Frameworks" >> ${CONFIG_MK}
-
-update_config_mk
diff --git a/libkc3_window/sdl2/demo/mandelbrot_f128.c b/libkc3_window/sdl2/demo/mandelbrot_f128.c
deleted file mode 100644
index 76e5208..0000000
--- a/libkc3_window/sdl2/demo/mandelbrot_f128.c
+++ /dev/null
@@ -1,320 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "../gl_deprecated.h"
-#include "../gl_font.h"
-#include "../mat4.h"
-#include "../gl_ortho.h"
-#include "../gl_text.h"
-#include "mandelbrot_f128.h"
-#include "window_sdl2_demo.h"
-
-static s_gl_font g_mandelbrot_f128_font = {0};
-static s_gl_text g_mandelbrot_f128_text = {0};
-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_button (s_sequence *seq, u8 button, sw x, sw y)
-{
- s_map *map;
- f128 *next_x;
- f128 *next_y;
- f128 *next_z;
- s_window_sdl2 *win;
- assert(seq);
- win = seq->window;
- assert(win);
- 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;
- if (button == 1) {
- *next_x = *next_x + *next_z * (x - (f128) win->w / 2);
- *next_y = *next_y + *next_z * ((f128) win->h / 2 - y);
- }
- else if (button == 5) {
- *next_z = *next_z * exp2l(0.5);
- }
- else if (button == 4) {
- *next_z = *next_z * exp2l(-0.5);
- }
- return true;
-}
-
-bool mandelbrot_f128_load (s_sequence *seq)
-{
- f32 point_per_pixel;
- s_map *map;
- s_window_sdl2 *window;
- assert(seq);
- window = seq->window;
- assert(window);
- point_per_pixel = (f32) window->w / window->gl_w;
- 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("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.0);
- if (! gl_font_init(&g_mandelbrot_f128_font,
- "fonts/Courier New/Courier New.ttf",
- point_per_pixel))
- return false;
- gl_font_set_size(&g_mandelbrot_f128_font, 20.0);
- if (! gl_text_init_1(&g_mandelbrot_f128_text, &g_mandelbrot_f128_font,
- "x: 0.0\n"
- "y: 0.0\n"
- "z: 0.01"))
- return false;
- gl_text_update(&g_mandelbrot_f128_text);
- assert(glGetError() == GL_NO_ERROR);
- glGenTextures(1, &g_mandelbrot_f128_texture);
- assert(glGetError() == GL_NO_ERROR);
- return true;
-}
-
-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("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[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)
- 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;
- }
- glClearColor(0, 0, 0, 0);
- glClear(GL_COLOR_BUFFER_BIT);
- mat4_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);
- gl_ortho_text_render_outline(&g_ortho, &g_mandelbrot_f128_text,
- 20.0, 66.0);
- 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, sym_1("U8[]"), 3, dim))
- return false;
- if (! array_allocate(pixels))
- return false;
- printf("mandelbrot_f128_resize: %lux%lu\n", win->w, win->h);
- return true;
-}
-
-bool mandelbrot_f128_unload (s_sequence *seq)
-{
- (void) seq;
- glDeleteTextures(1, &g_mandelbrot_f128_texture);
- gl_text_clean(&g_mandelbrot_f128_text);
- gl_font_clean(&g_mandelbrot_f128_font);
- return true;
-}
-
-static bool mandelbrot_f128_update (s_sequence *seq)
-{
- f128 _2z_xz_y;
- char a[512];
- s_buf buf;
- 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;
- s_array *pixels;
- u8 *pix;
- 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);
-#pragma omp parallel for private(c_x, c_y, j, k, z_x, z_y, z_x2, z_y2, _2z_xz_y, level)
- for (i = 0; i < win->h; i++) {
- c_y = next_y + next_z * ((f128) i - win->h / 2);
- j = 0;
- while (j < win->w) {
- c_x = next_x + next_z * ((f128) 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 = 255 - k;
- /*if (k)
- printf("x %lu, y %lu, k %d, level %d", j, i, k, level);*/
- pix[(i * win->w + j) * 4 + 0] = level;
- pix[(i * win->w + j) * 4 + 1] = level;
- pix[(i * win->w + j) * 4 + 2] = level;
- pix[(i * win->w + j) * 4 + 3] = 255;
- j++;
- }
- }
- assert(glGetError() == GL_NO_ERROR);
- glBindTexture(GL_TEXTURE_2D, g_mandelbrot_f128_texture);
- assert(glGetError() == GL_NO_ERROR);
- 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_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- assert(glGetError() == GL_NO_ERROR);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, win->w, win->h, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, pixels->data);
- assert(glGetError() == GL_NO_ERROR);
- buf_init(&buf, false, sizeof(a), a);
- buf_write_1(&buf, "x: ");
- buf_inspect_f128(&buf, &next_x);
- buf_write_1(&buf, "\ny: ");
- buf_inspect_f128(&buf, &next_y);
- buf_write_1(&buf, "\nz: ");
- buf_inspect_f128(&buf, &next_z);
- gl_text_update_buf(&g_mandelbrot_f128_text, &buf);
- printf("mandelbrot_f128_update: %lux%lu\n", win->w, win->h);
- return true;
-}
diff --git a/libkc3_window/sdl2/demo/mandelbrot_f128.h b/libkc3_window/sdl2/demo/mandelbrot_f128.h
deleted file mode 100644
index 3a95d69..0000000
--- a/libkc3_window/sdl2/demo/mandelbrot_f128.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 MANDELBROT_F128_H
-#define MANDELBROT_F128_H
-
-#include "../types.h"
-
-bool mandelbrot_f128_button (s_sequence *seq, u8 button, sw x, sw y);
-bool mandelbrot_f128_load (s_sequence *seq);
-bool mandelbrot_f128_render (s_sequence *seq);
-bool mandelbrot_f128_unload (s_sequence *seq);
-
-#endif /* MANDELBROT_F128_H */
diff --git a/libkc3_window/sdl2/demo/matrix.c b/libkc3_window/sdl2/demo/matrix.c
deleted file mode 100644
index 496029a..0000000
--- a/libkc3_window/sdl2/demo/matrix.c
+++ /dev/null
@@ -1,330 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "../gl_font.h"
-#include "../gl_ortho.h"
-#include "../gl_sprite.h"
-#include "../gl_vtext.h"
-#include "../mat4.h"
-#include "window_sdl2_demo.h"
-#include "matrix.h"
-
-#define MATRIX_FONT_SIZE 20
-#define MATRIX_TIME 0.1
-
-static s_gl_font g_matrix_font = {0};
-static s_gl_sprite g_matrix_shade = {0};
-static f64 g_matrix_time;
-
-void matrix_column_clean (s_tag *tag);
-bool matrix_column_init (s_sequence *seq, s_tag *tag);
-bool matrix_column_render (s_sequence *seq, s_tag *tag);
-void matrix_screen_clean (s_tag *tag);
-bool matrix_screen_init (s_tag *tag);
-bool matrix_screen_render (s_sequence *seq, s_tag *tag);
-void matrix_text_clean (s_tag *tag);
-bool matrix_text_init (s_tag *tag, f32 y);
-bool matrix_text_render (s_sequence *seq, const s_tag *tag, f32 **py);
-bool matrix_update (s_sequence *seq);
-
-void matrix_column_clean (s_tag *tag)
-{
- s_list *list;
- if (tag->type != TAG_LIST) {
- err_puts("matrix_column_clean: invalid tag");
- assert(! "matrix_column_clean: invalid tag");
- return;
- }
- list = tag->data.list;
- while (list) {
- matrix_text_clean(&list->tag);
- list = list_next(list);
- }
-}
-
-bool matrix_column_init (s_sequence *seq, s_tag *tag)
-{
- s_list *list;
- s_window_sdl2 *window;
- assert(seq);
- window = seq->window;
- assert(window);
- if (! (list = list_new(NULL)))
- return false;
- if (! matrix_text_init(&list->tag, window->h)) {
- list_delete_all(list);
- return false;
- }
- tag_init_list(tag, list);
- return true;
-}
-
-bool matrix_column_render (s_sequence *seq, s_tag *tag)
-{
- s_list **list;
- f32 *py;
- s_window_sdl2 *window;
- f32 y;
- assert(seq);
- assert(glGetError() == GL_NO_ERROR);
- window = seq->window;
- assert(window);
- if (!tag ||
- tag->type != TAG_LIST) {
- err_puts("matrix_column_render: invalid tag");
- assert(! "matrix_column_render: invalid tag");
- return false;
- }
- list = &tag->data.list;
- y = (*list)->tag.data.map.value[2].data.f32;
- if (y < window->h) {
- *list = list_new(*list);
- if (! matrix_text_init(&(*list)->tag, window->h))
- return false;
- }
- while (*list) {
- if (! matrix_text_render(seq, &(*list)->tag, &py))
- return false;
- if (*py < 0) {
- matrix_text_clean(&(*list)->tag);
- *list = list_delete(*list);
- }
- else
- list = &(*list)->next.data.list;
- }
- return true;
-}
-
-bool matrix_load (s_sequence *seq)
-{
- f32 point_per_pixel;
- s_window_sdl2 *window;
- assert(seq);
- assert(glGetError() == GL_NO_ERROR);
- window = seq->window;
- assert(window);
- point_per_pixel = (f32) window->w / window->gl_w;
- if (! gl_font_init(&g_matrix_font,
- "fonts/Noto Sans/NotoSans-Regular.ttf",
- point_per_pixel))
- return false;
- gl_font_set_size(&g_matrix_font, MATRIX_FONT_SIZE);
- if (! matrix_screen_init(&seq->tag))
- return false;
- if (! gl_sprite_init(&g_matrix_shade,
- "img/matrix_shade.png",
- 1, 1, 1, 1))
- return false;
- g_matrix_time = seq->t;
- return true;
-}
-
-bool matrix_render (s_sequence *seq)
-{
- assert(seq);
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- glClear(GL_COLOR_BUFFER_BIT);
- assert(glGetError() == GL_NO_ERROR);
- matrix_screen_render(seq, &seq->tag);
- assert(glGetError() == GL_NO_ERROR);
- if (seq->t - g_matrix_time > MATRIX_TIME)
- g_matrix_time = seq->t;
- return true;
-}
-
-void matrix_screen_clean (s_tag *tag)
-{
- s_list *list;
- if (! tag ||
- tag->type != TAG_LIST) {
- err_puts("matrix_screen_clean: invalid tag");
- assert(! "matrix_screen_clean: invalid tag");
- return;
- }
- list = tag->data.list;
- while (list) {
- matrix_column_clean(&list->tag);
- list = list_next(list);
- }
-}
-
-bool matrix_screen_init (s_tag *tag)
-{
- tag_init_list(tag, NULL);
- return true;
-}
-
-bool matrix_screen_render (s_sequence *seq, s_tag *tag)
-{
- s_list **l;
- s_list *list;
- s_mat4 matrix;
- s_window_sdl2 *window;
- f32 x;
- assert(seq);
- window = seq->window;
- assert(window);
- if (! tag ||
- tag->type != TAG_LIST) {
- err_puts("matrix_screen_render: invalid tag");
- assert(! "matrix_screen_render: invalid tag");
- return false;
- }
- x = 0;
- l = &tag->data.list;
- while (*l) {
- if (x > window->w) {
- matrix_column_clean(&(*l)->tag);
- *l = list_delete(*l);
- }
- else {
- x += MATRIX_FONT_SIZE;
- l = &(*l)->next.data.list;
- }
- }
- while (x < window->w) {
- *l = list_new(NULL);
- if (! matrix_column_init(seq, &(*l)->tag))
- return false;
- x += MATRIX_FONT_SIZE;
- l = &(*l)->next.data.list;
- }
- matrix = g_ortho.model_matrix; {
- list = tag->data.list;
- while (list) {
- if (! matrix_column_render(seq, &list->tag))
- return false;
- mat4_translate(&g_ortho.model_matrix, MATRIX_FONT_SIZE, 0, 0);
- list = list_next(list);
- }
- } g_ortho.model_matrix = matrix;
- return true;
-}
-
-bool matrix_text_init (s_tag *tag, f32 y)
-{
- char a[1024];
- s_buf buf;
- u8 i;
- u8 len;
- s_map *map;
- f32 spacing;
- s_gl_text *text;
- if (! tag_map(tag, 3))
- return false;
- buf_init(&buf, false, sizeof(a), a);
- u8_random_uniform(&i, 10);
- spacing = i * MATRIX_FONT_SIZE;
- u8_random_uniform(&len, 40);
- len += 10;
- text = gl_vtext_new(&g_matrix_font);
- if (! text)
- return false;
- if (! gl_vtext_render_to_texture_random(text, len)) {
- gl_vtext_delete(text);
- return false;
- }
- map = &tag->data.map;
- tag_init_sym( map->key + 0, sym_1("spacing"));
- tag_init_f32(map->value + 0, spacing);
- tag_init_sym( map->key + 1, sym_1("text"));
- tag_init_ptr(map->value + 1, text);
- tag_init_sym( map->key + 2, sym_1("y"));
- tag_init_f32(map->value + 2, y + text->pt_h + spacing);
- return true;
-}
-
-bool matrix_text_render (s_sequence *seq, const s_tag *tag, f32 **py)
-{
- const s_map *map;
- s_mat4 matrix;
- const s_gl_text *text;
- f32 *y;
- assert(seq);
- assert(glGetError() == GL_NO_ERROR);
- assert(tag);
- assert(tag->type == TAG_MAP);
- map = &tag->data.map;
- assert(map->count == 3);
- /*
- assert( map->key[0].type == TAG_SYM);
- assert( map->key[0].data.sym == sym_1("spacing"));
- assert( map->value[0].type == TAG_F32);
- spacing = &map->value[0].data.f32;
- */
- assert( map->key[1].type == TAG_SYM);
- assert( map->key[1].data.sym == sym_1("text"));
- assert(map->value[1].type == TAG_PTR);
- text = map->value[1].data.ptr.p;
- assert( map->key[2].type == TAG_SYM);
- assert( map->key[2].data.sym == sym_1("y"));
- assert(map->value[2].type == TAG_F32);
- y = &map->value[2].data.f32;
- if (seq->t - g_matrix_time > MATRIX_TIME)
- *y -= MATRIX_FONT_SIZE;
- matrix = g_ortho.model_matrix; {
- //printf("y %f\n", *y);
- mat4_translate(&g_ortho.model_matrix,
- (MATRIX_FONT_SIZE - text->pt_w) / 2, *y, 0);
- gl_ortho_update_model_matrix(&g_ortho);
- assert(glGetError() == GL_NO_ERROR);
- gl_ortho_color(&g_ortho, 0, 1, 0, 1);
- assert(glGetError() == GL_NO_ERROR);
- glEnable(GL_BLEND);
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
- GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- gl_ortho_vtext_render(&g_ortho, text);
- assert(glGetError() == GL_NO_ERROR);
- glDisable(GL_DEPTH_TEST);
- gl_ortho_color(&g_ortho, 1, 1, 1, 1);
- gl_ortho_bind_texture(&g_ortho,
- gl_sprite_texture(&g_matrix_shade, 0));
- assert(glGetError() == GL_NO_ERROR);
- gl_ortho_rect(&g_ortho, 0, MATRIX_FONT_SIZE - text->pt_h,
- text->pt_w, text->pt_h - MATRIX_FONT_SIZE);
- } g_ortho.model_matrix = matrix;
- assert(glGetError() == GL_NO_ERROR);
- glDisable(GL_BLEND);
- assert(glGetError() == GL_NO_ERROR);
- *py = y;
- return true;
-}
-
-void matrix_text_clean (s_tag *tag)
-{
- s_map *map;
- s_gl_text *text;
- if (! (tag->type == TAG_MAP &&
- (map = &tag->data.map) &&
- map->count == 3 &&
- map->key[1].type == TAG_SYM &&
- map->key[1].data.sym == sym_1("text") &&
- map->value[1].type == TAG_PTR &&
- (text = map->value[1].data.ptr.p))) {
- err_puts("matrix_text_clean: invalid tag");
- assert(! "matrix_text_clean: invalid tag");
- return;
- }
- gl_vtext_delete(text);
-}
-
-bool matrix_unload (s_sequence *seq)
-{
- assert(seq);
- matrix_screen_clean(&seq->tag);
- tag_void(&seq->tag);
- gl_font_clean(&g_matrix_font);
- gl_sprite_clean(&g_matrix_shade);
- return true;
-}
diff --git a/libkc3_window/sdl2/demo/matrix.h b/libkc3_window/sdl2/demo/matrix.h
deleted file mode 100644
index f97bc13..0000000
--- a/libkc3_window/sdl2/demo/matrix.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 MATRIX_H
-#define MATRIX_H
-
-#include "../types.h"
-
-bool matrix_load (s_sequence *seq);
-bool matrix_render (s_sequence *seq);
-bool matrix_unload (s_sequence *seq);
-
-#endif /* MATRIX_H */
diff --git a/libkc3_window/sdl2/demo/sources.mk b/libkc3_window/sdl2/demo/sources.mk
deleted file mode 100644
index 95ffd97..0000000
--- a/libkc3_window/sdl2/demo/sources.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-# sources.mk generated by update_sources
-HEADERS = \
- "bg_rect.h" \
- "earth.h" \
- "flies.h" \
- "lightspeed.h" \
- "mandelbrot_f128.h" \
- "matrix.h" \
- "toasters.h" \
- "window_sdl2_demo.h" \
-
-SOURCES = \
- "bg_rect.c" \
- "earth.c" \
- "flies.c" \
- "lightspeed.c" \
- "mandelbrot_f128.c" \
- "matrix.c" \
- "toasters.c" \
- "window_sdl2_demo.c" \
-
diff --git a/libkc3_window/sdl2/demo/sources.sh b/libkc3_window/sdl2/demo/sources.sh
deleted file mode 100644
index f2e1eca..0000000
--- a/libkc3_window/sdl2/demo/sources.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-# sources.sh generated by update_sources
-HEADERS='bg_rect.h earth.h flies.h lightspeed.h mandelbrot_f128.h matrix.h toasters.h window_sdl2_demo.h '
-SOURCES='bg_rect.c earth.c flies.c lightspeed.c mandelbrot_f128.c matrix.c toasters.c window_sdl2_demo.c '
diff --git a/libkc3_window/sdl2/demo/toasters.c b/libkc3_window/sdl2/demo/toasters.c
deleted file mode 100644
index 775fb1b..0000000
--- a/libkc3_window/sdl2/demo/toasters.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "../mat4.h"
-#include "../gl_ortho.h"
-#include "../gl_sprite.h"
-#include "toasters.h"
-#include "window_sdl2_demo.h"
-
-#define TOASTERS_SCALE_TOAST 0.52
-#define TOASTERS_SCALE_TOASTER 0.4
-#define TOASTERS_SPACING \
- (g_sprite_toaster.pt_h * TOASTERS_SCALE_TOASTER * 2.0)
-
-static const f64 g_speed_x = 80.0;
-static const f64 g_speed_y = -40.0;
-s_gl_sprite g_sprite_toast = {0};
-s_gl_sprite g_sprite_toaster = {0};
-
-static bool toasters_render_toasters (s_list **toasters,
- s_window_sdl2 *window,
- s_sequence *seq);
-static bool toasters_render_toasts (s_list **toasts,
- s_window_sdl2 *window,
- s_sequence *seq);
-
-static s_tag * toast_init (s_tag *toast, f64 x, f64 y)
-{
- tag_init_map(toast, 2);
- tag_init_sym(toast->data.map.key + 0, sym_1("x"));
- tag_init_f64(toast->data.map.value + 0, x);
- tag_init_sym(toast->data.map.key + 1, sym_1("y"));
- tag_init_f64(toast->data.map.value + 1, y);
- return toast;
-}
-
-
-static void toast_render (s_tag *toast, s_window_sdl2 *window,
- s_sequence *seq)
-{
- s_mat4 matrix;
- GLuint texture;
- f64 *x;
- f64 *y;
- if (toast->type == TAG_MAP) {
- x = &toast->data.map.value[0].data.f64;
- y = &toast->data.map.value[1].data.f64;
- *x -= seq->dt * g_speed_x;
- *y -= seq->dt * g_speed_y;
- if (*x < -100 || *y > window->h) {
- tag_clean(toast);
- toast->type = TAG_VOID;
- return;
- }
- matrix = g_ortho.model_matrix; {
- mat4_translate(&g_ortho.model_matrix, *x,
- *y + g_sprite_toast.pt_h, 0.0);
- mat4_scale(&g_ortho.model_matrix,
- TOASTERS_SCALE_TOAST,
- -TOASTERS_SCALE_TOAST, 1);
- gl_ortho_update_model_matrix(&g_ortho);
- texture = gl_sprite_texture(&g_sprite_toast, 0);
- gl_ortho_bind_texture(&g_ortho, texture);
- gl_ortho_rect(&g_ortho, 0, 0, g_sprite_toast.pt_w,
- g_sprite_toast.pt_h);
- } g_ortho.model_matrix = matrix;
- }
-}
-
-static s_tag * toaster_init (s_tag *toaster, f64 y)
-{
- tag_init_map(toaster, 2);
- tag_init_sym(toaster->data.map.key + 0, sym_1("x"));
- tag_init_f64(toaster->data.map.value + 0, -150);
- tag_init_sym(toaster->data.map.key + 1, sym_1("y"));
- tag_init_f64(toaster->data.map.value + 1, y);
- return toaster;
-}
-
-static void toaster_render (s_tag *toaster, s_window_sdl2 *window,
- s_sequence *seq)
-{
- s_mat4 matrix;
- GLuint texture;
- f64 *x;
- f64 *y;
- if (toaster->type == TAG_MAP) {
- x = &toaster->data.map.value[0].data.f64;
- y = &toaster->data.map.value[1].data.f64;
- *x += seq->dt * g_speed_x;
- *y += seq->dt * g_speed_y;
- if (*x > window->w || *y < -300) {
- tag_clean(toaster);
- toaster->type = TAG_VOID;
- return;
- }
- matrix = g_ortho.model_matrix;
- mat4_translate(&g_ortho.model_matrix, *x,
- *y + g_sprite_toaster.pt_h, 0.0);
- mat4_scale(&g_ortho.model_matrix,
- TOASTERS_SCALE_TOASTER,
- -TOASTERS_SCALE_TOASTER, 1);
- gl_ortho_update_model_matrix(&g_ortho);
- texture = gl_sprite_texture(&g_sprite_toaster,
- fmod(seq->t *
- g_sprite_toaster.frame_count,
- g_sprite_toaster.frame_count));
- gl_ortho_bind_texture(&g_ortho, texture);
- gl_ortho_rect(&g_ortho, 0, 0, g_sprite_toaster.pt_w,
- g_sprite_toaster.pt_h);
- g_ortho.model_matrix = matrix;
- }
-}
-
-bool toasters_load (s_sequence *seq)
-{
- s_map *map;
- tag_map(&seq->tag, 2);
- map = &seq->tag.data.map;
- tag_init_sym( map->key + 0, sym_1("toasters"));
- tag_init_list(map->value + 0, NULL);
- tag_init_sym( map->key + 1, sym_1("toasts"));
- tag_init_list(map->value + 1, NULL);
- return true;
-}
-
-bool toasters_render (s_sequence *seq)
-{
- s_list **toasters;
- s_list **toasts;
- s_window_sdl2 *window;
- assert(seq);
- window = seq->window;
- assert(window);
- glClearColor(0.7f, 0.95f, 1.0f, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT);
- mat4_init_identity(&g_ortho.model_matrix);
- mat4_translate(&g_ortho.model_matrix, 0, window->h, 0);
- mat4_scale(&g_ortho.model_matrix, 1, -1, 1);
- /* io_inspect(&seq->tag); */
- if (seq->tag.type == TAG_MAP) {
- toasters = &seq->tag.data.map.value[0].data.list;
- toasts = &seq->tag.data.map.value[1].data.list;
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
- GL_LINEAR_MIPMAP_LINEAR);
- toasters_render_toasts(toasts, window, seq);
- toasters_render_toasters(toasters, window, seq);
- }
- return true;
-}
-
-bool toasters_render_toasts (s_list **toasts, s_window_sdl2 *window,
- s_sequence *seq)
-{
- s_list *i;
- s_list *j;
- s_map *map;
- s_list **t = NULL;
- f64 x;
- f64 y;
- assert(toasts);
- assert(window);
- assert(seq);
- y = window->w * g_speed_y / g_speed_x -
- TOASTERS_SPACING * 3.0 / 2.0 +
- 50;
- if (*toasts && (*toasts)->tag.type == TAG_MAP) {
- t = &(*toasts)->tag.data.map.value[0].data.list;
- y = (*toasts)->tag.data.map.value[1].data.f64;
- }
- while (y < window->h - TOASTERS_SPACING / 2) {
- y += TOASTERS_SPACING;
- *toasts = list_new_map(2, *toasts);
- map = &(*toasts)->tag.data.map;
- tag_init_sym( map->key + 0, sym_1("toasts"));
- tag_init_list(map->value + 0, NULL);
- tag_init_sym( map->key + 1, sym_1("y"));
- tag_init_f64(map->value + 1, y);
- }
- i = *toasts;
- while (i) {
- if (i->tag.type == TAG_MAP) {
- t = &i->tag.data.map.value[0].data.list;
- y = i->tag.data.map.value[1].data.f64;
- x = 0.0;
- if (*t && (*t)->tag.type == TAG_MAP)
- x = (*t)->tag.data.map.value[0].data.f64;
- if (x < window->w - 160.0) {
- *t = list_new(*t);
- toast_init(&(*t)->tag, window->w, y);
- }
- list_remove_void(t);
- j = *t;
- while (j) {
- toast_render(&j->tag, window, seq);
- j = list_next(j);
- }
- }
- i = list_next(i);
- }
- return true;
-}
-
-bool toasters_render_toasters (s_list **toasters, s_window_sdl2 *window,
- s_sequence *seq)
-{
- s_list *i;
- s_list *j;
- s_map *map;
- s_list **t = NULL;
- f64 x;
- f64 y;
- assert(toasters);
- assert(window);
- assert(seq);
- /* io_inspect_list((const s_list **) toasters); */
- y = -TOASTERS_SPACING - 40;
- if (*toasters && (*toasters)->tag.type == TAG_MAP) {
- t = &(*toasters)->tag.data.map.value[0].data.list;
- y = (*toasters)->tag.data.map.value[1].data.f64;
- }
- while (y < window->h - window->w * g_speed_y / g_speed_x +
- TOASTERS_SPACING) {
- y += TOASTERS_SPACING;
- *toasters = list_new_map(2, *toasters);
- map = &(*toasters)->tag.data.map;
- tag_init_sym( map->key + 0, sym_1("toasters"));
- tag_init_list(map->value + 0, NULL);
- tag_init_sym( map->key + 1, sym_1("y"));
- tag_init_f64(map->value + 1, y);
- }
- i = *toasters;
- while (i) {
- if (i->tag.type == TAG_MAP) {
- t = &i->tag.data.map.value[0].data.list;
- y = i->tag.data.map.value[1].data.f64;
- x = 1000.0;
- if (*t && (*t)->tag.type == TAG_MAP)
- x = (*t)->tag.data.map.value[0].data.f64;
- if (x > 60.0) {
- *t = list_new(*t);
- toaster_init(&(*t)->tag, y);
- }
- list_remove_void(t);
- j = *t;
- while (j) {
- toaster_render(&j->tag, window, seq);
- j = list_next(j);
- }
- }
- i = list_next(i);
- }
- return true;
-}
-
-bool toasters_unload (s_sequence *seq)
-{
- (void) seq;
- return true;
-}
diff --git a/libkc3_window/sdl2/demo/toasters.h b/libkc3_window/sdl2/demo/toasters.h
deleted file mode 100644
index ab0a583..0000000
--- a/libkc3_window/sdl2/demo/toasters.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 TOASTERS_H
-#define TOASTERS_H
-
-#include "../types.h"
-
-extern s_gl_sprite g_sprite_toast;
-extern s_gl_sprite g_sprite_toaster;
-
-bool toasters_load (s_sequence *seq);
-bool toasters_render (s_sequence *seq);
-bool toasters_unload (s_sequence *seq);
-
-#endif /* TOASTERS_H */
diff --git a/libkc3_window/sdl2/demo/update_sources b/libkc3_window/sdl2/demo/update_sources
deleted file mode 100755
index 0c17b11..0000000
--- a/libkc3_window/sdl2/demo/update_sources
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-. ../../../config.subr
-
-echo "$PWD/update_sources"
-
-echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
-echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
-
-HEADERS="$(ls *.h | grep -v '^config.h$')"
-sources HEADERS "$HEADERS"
-
-SOURCES="$(ls *.c)"
-sources SOURCES "$SOURCES"
-
-update_sources_mk
-update_sources_sh
diff --git a/libkc3_window/sdl2/demo/window_sdl2_demo.c b/libkc3_window/sdl2/demo/window_sdl2_demo.c
deleted file mode 100644
index 955f14a..0000000
--- a/libkc3_window/sdl2/demo/window_sdl2_demo.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <stdio.h>
-#include <stdlib.h>
-#include <libkc3/kc3.h>
-#include "../../window.h"
-#include "../gl_font.h"
-#include "../gl_lines.h"
-#include "../mat4.h"
-#include "../gl_ortho.h"
-#include "../gl_square.h"
-#include "../gl_text.h"
-#include "../gl_sprite.h"
-#include "../window_sdl2.h"
-#include "bg_rect.h"
-#include "lightspeed.h"
-#include "toasters.h"
-#include "flies.h"
-#include "earth.h"
-#include "mandelbrot_f128.h"
-#include "matrix.h"
-
-#define WINDOW_SDL2_DEMO_SEQUENCE_COUNT 7
-
-//s_gl_font g_font_computer_modern = {0};
-s_gl_font g_font_courier_new = {0};
-s_gl_ortho g_ortho = {0};
-s_gl_square g_square = {0};
-s_gl_text g_text_fps = {0};
-s_gl_text g_text_seq_title = {0};
-
-static bool window_sdl2_demo_button (s_window_sdl2 *window, u8 button,
- sw x, sw y);
-static bool window_sdl2_demo_key (s_window_sdl2 *window,
- SDL_Keysym *keysym);
-static bool window_sdl2_demo_load (s_window_sdl2 *window);
-static bool window_sdl2_demo_render (s_window_sdl2 *window);
-static bool window_sdl2_demo_resize (s_window_sdl2 *window,
- uw w, uw h);
-static void window_sdl2_demo_unload (s_window_sdl2 *window);
-
-int main (int argc, char **argv)
-{
- s_window_sdl2 window;
- if (FT_Init_FreeType(&g_ft)) {
- err_puts("main: failed to initialize FreeType");
- return 1;
- }
- if (! kc3_init(NULL, &argc, &argv)) {
- err_puts("kc3_init");
- return 1;
- }
- window_sdl2_init(&window, 50, 50, 800, 600,
- "KC3.Window.SDL2 demo",
- WINDOW_SDL2_DEMO_SEQUENCE_COUNT);
- window.button = window_sdl2_demo_button;
- window.key = window_sdl2_demo_key;
- window.load = window_sdl2_demo_load;
- window.render = window_sdl2_demo_render;
- window.resize = window_sdl2_demo_resize;
- window.unload = window_sdl2_demo_unload;
- if (! window_sdl2_run(&window)) {
- err_puts("window_sdl2_run -> false");
- window_sdl2_clean(&window);
- kc3_clean(NULL);
- SDL_Quit();
- return g_kc3_exit_code;
- }
- window_sdl2_clean(&window);
- kc3_clean(NULL);
- SDL_Quit();
- FT_Done_FreeType(g_ft);
- return 0;
-}
-
-bool window_sdl2_demo_button (s_window_sdl2 *window, u8 button,
- sw x, sw y)
-{
- assert(window);
- (void) window;
- printf("kc3_window_sdl2_demo_button: %lu (%ld, %ld)\n", (uw) button, x, y);
- if (window->seq && window->seq->button &&
- ! window->seq->button(window->seq, button, x, y))
- return false;
- return true;
-}
-
-bool window_sdl2_demo_key (s_window_sdl2 *window, SDL_Keysym *keysym)
-{
- assert(window);
- assert(keysym);
- (void) window;
- switch (keysym->sym) {
- case SDLK_f:
- if (! window->fullscreen) {
- if (SDL_SetWindowFullscreen(window->sdl_window,
- SDL_WINDOW_FULLSCREEN_DESKTOP)) {
- err_write_1("window_sdl2_demo_key:"
- " SDL_SetWindowFullscreen(:desktop): ");
- err_puts(SDL_GetError());
- SDL_MaximizeWindow(window->sdl_window);
- }
- }
- else {
- if (SDL_SetWindowFullscreen(window->sdl_window, 0)) {
- err_write_1("window_sdl2_demo_key:"
- " SDL_SetWindowFullscreen(0): ");
- err_puts(SDL_GetError());
- SDL_RestoreWindow(window->sdl_window);
- }
- }
- window->fullscreen = ! window->fullscreen;
- return true;
- case SDLK_ESCAPE:
- case SDLK_q:
- g_kc3_exit_code = 0;
- return false;
- case SDLK_LEFT:
- if (! window_set_sequence_pos((s_window *) window,
- (window->sequence_pos +
- window->sequence_count - 1) %
- window->sequence_count))
- return false;
- break;
- case SDLK_RIGHT:
- if (! window_set_sequence_pos((s_window *) window,
- (window->sequence_pos + 1) %
- window->sequence_count))
- return false;
- break;
- default:
- printf("kc3_window_sdl2_demo_key: %d\n", keysym->sym);
- }
- return true;
-}
-
-bool window_sdl2_demo_load (s_window_sdl2 *window)
-{
- f32 point_per_pixel;
- assert(window);
- assert(glGetError() == GL_NO_ERROR);
- point_per_pixel = (f32) window->w / window->gl_w;
- err_write_1("point_per_pixel: ");
- err_inspect_f32(&point_per_pixel);
- err_write_1("\n");
- if (window->sequence_count != WINDOW_SDL2_DEMO_SEQUENCE_COUNT) {
- fprintf(stderr, "window_sdl2_demo_load: "
- "window->sequence_count = %lu\n", window->sequence_count);
- assert(window->sequence_count == WINDOW_SDL2_DEMO_SEQUENCE_COUNT);
- return false;
- }
- if (! gl_ortho_init(&g_ortho))
- return false;
- gl_ortho_resize(&g_ortho, 0, window->w, 0, window->h, 0, 1);
- if (! gl_font_init(&g_font_courier_new,
- "fonts/Courier New/Courier New.ttf",
- point_per_pixel))
- return false;
- if (! gl_text_init_1(&g_text_seq_title, &g_font_courier_new, ""))
- return false;
- if (! gl_text_init_1(&g_text_fps, &g_font_courier_new, "0.00"))
- return false;
- sequence_init(window->sequence, 8.0, "01. Background rectangles",
- bg_rect_load, bg_rect_render, bg_rect_unload, window);
- if (! gl_lines_init(&g_lines_stars) ||
- ! gl_lines_allocate(&g_lines_stars, LIGHTSPEED_STAR_MAX))
- return false;
- sequence_init(window->sequence + 1, 20.0, "02. Lightspeed",
- lightspeed_load, lightspeed_render, lightspeed_unload,
- window);
- if (! gl_sprite_init(&g_sprite_toaster, "img/flaps.256.png",
- 4, 1, 4, 1))
- return false;
- if (! gl_sprite_init(&g_sprite_toast, "img/toast.128.png",
- 1, 1, 1, 1))
- return false;
- sequence_init(window->sequence + 2, 60.0, "03. Toasters",
- toasters_load, toasters_render, toasters_unload,
- window);
- if (! gl_font_init(&g_font_flies,
- "fonts/Courier New/Courier New.ttf",
- point_per_pixel))
- return false;
- if (! gl_sprite_init(&g_sprite_fly, "img/fly-noto.png",
- 1, 1, 1, point_per_pixel))
- return false;
- if (! gl_sprite_init(&g_sprite_dead_fly, "img/fly-dead.png",
- 1, 1, 1, point_per_pixel))
- return false;
- sequence_init(window->sequence + 3, 60.0, "04. Flies",
- flies_load, flies_render, flies_unload, window);
- if (! gl_sprite_init(&g_sprite_earth, "img/earth.png",
- 1, 1, 1, point_per_pixel))
- return false;
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- assert(glGetError() == GL_NO_ERROR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- assert(glGetError() == GL_NO_ERROR);
- sequence_init(window->sequence + 4, 120.0, "05. Earth",
- earth_load, earth_render, earth_unload, window);
- sequence_init(window->sequence + 5, 3600.0, "06. Mandelbrot (f128)",
- mandelbrot_f128_load, mandelbrot_f128_render,
- mandelbrot_f128_unload, window);
- window->sequence[5].button = mandelbrot_f128_button;
- sequence_init(window->sequence + 6, 3600.0, "07. Matrix",
- matrix_load, matrix_render,
- matrix_unload, window);
- window_set_sequence_pos((s_window *) window, 0);
- return true;
-}
-
-bool window_sdl2_demo_render (s_window_sdl2 *window)
-{
- s_sequence *seq;
- assert(window);
- assert(glGetError() == GL_NO_ERROR);
- if (! window_animate((s_window *) window))
- return false;
- seq = window->seq;
- mat4_init_identity(&g_ortho.model_matrix);
- gl_ortho_render(&g_ortho);
- glDisable(GL_DEPTH_TEST);
- glEnable(GL_BLEND);
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
- GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- assert(glGetError() == GL_NO_ERROR);
- if (! seq->render(seq))
- return false;
- assert(glGetError() == GL_NO_ERROR);
- /* 2D */
- gl_ortho_render(&g_ortho);
- glDisable(GL_DEPTH_TEST);
- glEnable(GL_BLEND);
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
- GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- assert(glGetError() == GL_NO_ERROR);
- gl_font_set_size(&g_font_courier_new, 20);
- gl_text_update_1(&g_text_seq_title, seq->title);
- mat4_init_identity(&g_ortho.model_matrix);
- gl_ortho_text_render_outline(&g_ortho, &g_text_seq_title,
- 20.0f, 30.0f);
- /* progress bar */
- mat4_init_identity(&g_ortho.model_matrix);
- glDisable(GL_BLEND);
- assert(glGetError() == GL_NO_ERROR);
- gl_ortho_bind_texture(&g_ortho, 0);
- assert(glGetError() == GL_NO_ERROR);
- gl_ortho_color(&g_ortho, 1.0f, 1.0f, 1.0f, 1.0f);
- gl_ortho_rect(&g_ortho, 19, 11,
- (window->w - 40.0) * seq->t / seq->duration + 2,
- 4);
- gl_ortho_color(&g_ortho, 0.0f, 0.0f, 0.0f, 1.0f);
- gl_ortho_rect(&g_ortho, 20, 12,
- (window->w - 40.0) * seq->t / seq->duration,
- 2);
- /* fps */
- char fps[32];
- snprintf(fps, sizeof(fps), "%.1f", (f64) seq->frame / seq->t);
- mat4_init_identity(&g_ortho.model_matrix);
- gl_text_update_1(&g_text_fps, fps);
- glEnable(GL_BLEND);
- gl_ortho_text_render_outline(&g_ortho, &g_text_fps,
- 20, window->h - 30);
- gl_ortho_render_end(&g_ortho);
- return true;
-}
-
-bool window_sdl2_demo_resize (s_window_sdl2 *window,
- uw w, uw h)
-{
- assert(window);
- (void) window;
- assert(glGetError() == GL_NO_ERROR);
- gl_ortho_resize(&g_ortho, 0, w, 0, h, 0, 1);
- assert(glGetError() == GL_NO_ERROR);
- return true;
-}
-
-void window_sdl2_demo_unload (s_window_sdl2 *window)
-{
- assert(window);
- (void) window;
- if (g_ortho.gl_shader_program) {
- gl_ortho_clean(&g_ortho);
- gl_font_clean(&g_font_courier_new);
- gl_sprite_clean(&g_sprite_toaster);
- gl_sprite_clean(&g_sprite_toast);
- gl_font_clean(&g_font_flies);
- gl_sprite_clean(&g_sprite_fly);
- gl_sprite_clean(&g_sprite_dead_fly);
- gl_sprite_clean(&g_sprite_earth);
- }
-}
diff --git a/libkc3_window/sdl2/demo/window_sdl2_demo.h b/libkc3_window/sdl2/demo/window_sdl2_demo.h
deleted file mode 100644
index 3cccff5..0000000
--- a/libkc3_window/sdl2/demo/window_sdl2_demo.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_SDL2_DEMO_H
-#define LIBKC3_WINDOW_SDL2_DEMO_H
-
-#include "../types.h"
-
-extern s_gl_font g_font_computer_modern;
-extern s_gl_font g_font_courier_new;
-
-extern s_gl_ortho g_ortho;
-
-#endif /* LIBKC3_WINDOW_SDL2_DEMO_H */
diff --git a/libkc3_window/sdl2/disabled/mandelbrot.c b/libkc3_window/sdl2/disabled/mandelbrot.c
deleted file mode 100644
index e36e6c6..0000000
--- a/libkc3_window/sdl2/disabled/mandelbrot.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "mandelbrot.h"
-
-GLuint g_mandelbrotComputeProgram = 0;
-GLuint g_mandelbrotComputeShader = 0;
-
-bool mandelbrot_load (s_sequence *seq, s_window_sdl2 *window)
-{
- uw i;
- uw star_count;
- s_map *map;
- (void) window;
- if (! tag_map(&seq->tag, 5))
- return false;
- map = &seq->tag.data.map;
- tag_init_sym_1(map->key + 0, "h");
- tag_init_uw( map->value + 0, 0);
- tag_init_sym_1(map->key + 1, "w");
- tag_init_uw( map->value + 1, 0);
- tag_init_sym_1(map->key + 2, "x");
- tag_init_f64(map->value + 2, 0.0);
- tag_init_sym_1(map->key + 3, "y");
- tag_init_f64(map->value + 3, 0.0);
- tag_init_sym_1(map->key + 4, "zoom");
- tag_init_f64(map->value + 4, 1.0);
- return true;
-}
-
-bool mandelbrot_render (s_sequence *seq, s_window_sdl2 *window,
- void *context)
-{
- uw *h;
- s_map *map;
- uw *w;
- f64 *x;
- f64 *y;
- f64 *zoom;
- assert(seq);
- assert(window);
- (void) context;
- if (seq->tag.type != TAG_MAP) {
- err_puts("mandelbrot_render: sequence tag is not a map");
- assert(! "mandelbrot_render: sequence tag is not a map");
- return false;
- }
- map = &seq->tag.data.map;
- if (map->count != 5 ||
- map->value[0].type != TAG_UW ||
- map->value[1].type != TAG_UW ||
- map->value[2].type != TAG_F64 ||
- map->value[3].type != TAG_F64 ||
- map->value[4].type != TAG_F64) {
- err_puts("mandelbrot_render: invalid map");
- assert(! "mandelbrot_render: invalid map");
- return false;
- }
- h = &map->value[0].data.uw;
- w = &map->value[1].data.uw;
- x = &map->value[2].data.f64;
- y = &map->value[3].data.f64;
- zoom = &map->value[4].data.f64;
- if (*w != window->w || *h != window->h) {
- *w = window->w;
- *h = window->h;
- mandelbrot_texture_update(*w, *h);
- }
- // fullscreen texture
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- glColor4f(1, 1, 1, 1);
- glDisable(GL_BLEND);
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_CULL_FACE);
- glEnable(GL_TEXTURE_2D);
- glBegin(GL_QUADS); {
- glTexCoord2f(0, 1);
- glVertex2f(-1, 1);
- glTexCoord2f(0, 0);
- glVertex2f(-1, -1);
- glTexCoord2f(1, 0);
- glVertex2f(1, -1);
- glTexCoord2f(1, 1);
- glVertex2f(1, 1);
- } glEnd();
- return true;
-}
-
-void mandelbrot_shader_init (void)
-{
- const char* src =
- "#version 430 core\n"
- "layout (local_size_x = 16, local_size_y = 16) in;\n"
- "layout (rgba32f, binding = 0) uniform image2D mandelbrotImage;\n"
- "uniform int maxIterations;\n"
- "uniform double zoom;\n"
- "uniform dvec2 offset;\n"
- "void main() {\n"
- " ivec2 texelCoord = ivec2(gl_GlobalInvocationID.xy);\n"
- " dvec2 c = (dvec2(texelCoord) /\n"
- " double(imageSize(mandelbrotImage).y) - 0.5) *\n"
- " zoom + offset;\n"
- " dvec2 z = c;\n"
- " int iterations = 0;\n"
- " for (int i = 0; i < maxIterations; ++i) {\n"
- " if (dot(z, z) > 4.0) {\n"
- " break;\n"
- " }\n"
- " z = dvec2(z.x * z.x - z.y * z.y, 2.0 * z.x * z.y) + c;\n"
- " iterations++;\n"
- " }\n"
- " vec4 color = vec4(float(iterations) / float(maxIterations));\n"
- " imageStore(mandelbrotImage, texelCoord, color);\n"
- "}\n";
- g_mandelbrot_shader = glCreateShader(GL_COMPUTE_SHADER);
- glShaderSource(g_mandelbrot_shader, 1, src, NULL);
- glCompileShader(g_mandelbrot_shader);
- g_mandelbrotShaderProgram = glCreateProgram();
- glAttachShader(mandelbrotShaderProgram, g_mandelbrot_shader);
- glLinkProgram(mandelbrotShaderProgram);
- glUseProgram(mandelbrotShaderProgram);
-}
-
-void mandelbrot_texture_delete (void)
-{
- glDeleteTextures(1, &g_mandelbrot_texture);
-}
-
-void mandelbrot_texture_init (void)
-{
- glGenTextures(1, &g_mandelbrot_texture);
-}
-
-void mandelbrot_update_texture () {
- glBindTexture(GL_TEXTURE_2D, mandelbrotImage);
- glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, WIDTH, HEIGHT);
- glBindImageTexture(0, mandelbrotImage, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
-}
diff --git a/libkc3_window/sdl2/disabled/mandelbrot.h b/libkc3_window/sdl2/disabled/mandelbrot.h
deleted file mode 100644
index 6ab1aff..0000000
--- a/libkc3_window/sdl2/disabled/mandelbrot.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 MANDELBROT_H
-#define MANDELBROT_H
-
-#include "../types.h"
-
-bool mandelbrot_load (s_sequence *seq, s_window_sdl2 *window);
-bool mandelbrot_render (s_sequence *seq, s_window_sdl2 *window,
- void *context);
-
-#endif /* MANDELBROT_H */
diff --git a/libkc3_window/sdl2/disabled/sdl2_font.c b/libkc3_window/sdl2/disabled/sdl2_font.c
deleted file mode 100644
index d290efb..0000000
--- a/libkc3_window/sdl2/disabled/sdl2_font.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "sdl2_font.h"
-
-void sdl2_font_clean (s_sdl2_font *font)
-{
- assert(font);
- if (font->ftgl_font)
- ftglDestroyFont(font->ftgl_font);
- str_clean(&font->path);
- str_clean(&font->real_path);
-}
-
-s_sdl2_font * sdl2_font_init (s_sdl2_font *font, const s8 *path)
-{
- assert(font);
- assert(path);
- str_init_copy_1(&font->path, path);
- if (! file_search(&font->path, sym_1("r"), &font->real_path)) {
- err_write_1("sdl2_font_init: file not found: ");
- err_puts(path);
- str_clean(&font->path);
- return NULL;
- }
- assert(glGetError() == GL_NO_ERROR);
- font->ftgl_font = ftglCreateTextureFont(font->real_path.ptr.ps8);
- if (! font->ftgl_font) {
- err_write_1("sdl2_font_init: error loading font: ");
- err_puts(font->real_path.ptr.ps8);
- str_clean(&font->path);
- str_clean(&font->real_path);
- return NULL;
- }
- assert(glGetError() == GL_NO_ERROR);
- font->size = 0;
- font->dpi = 72;
- return font;
-}
-
-void sdl2_font_set_size (s_sdl2_font *font, u32 size, u32 dpi)
-{
- assert(font);
- assert(size);
- ftglSetFontFaceSize(font->ftgl_font, size, dpi);
- font->size = size;
- font->dpi = dpi;
-}
-
-void sdl2_font_render_text (const s_sdl2_font *font, const s8 *p)
-{
- assert(glGetError() == GL_NO_ERROR);
- ftglRenderFont(font->ftgl_font, p, FTGL_RENDER_ALL);
- assert(glGetError() == GL_NO_ERROR);
-}
diff --git a/libkc3_window/sdl2/disabled/sdl2_font.h b/libkc3_window/sdl2/disabled/sdl2_font.h
deleted file mode 100644
index 2e41777..0000000
--- a/libkc3_window/sdl2/disabled/sdl2_font.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_SDL2_SDL2_FONT_H
-#define LIBKC3_WINDOW_SDL2_SDL2_FONT_H
-
-#include "types.h"
-
-/* Stack-allocation compatible functions, call sdl2_font_clean after
- use. */
-void sdl2_font_clean (s_sdl2_font *font);
-s_sdl2_font * sdl2_font_init (s_sdl2_font *font, const s8 *path);
-
-/* Operators. */
-void sdl2_font_set_size (s_sdl2_font *font, u32 size, u32 dpi);
-
-/* Observers */
-void sdl2_font_render_text (const s_sdl2_font *font, const s8 *p);
-
-#endif /* LIBKC3_WINDOW_SDL2_SDL2_FONT_H */
diff --git a/libkc3_window/sdl2/disabled/sdl2_sprite.c b/libkc3_window/sdl2/disabled/sdl2_sprite.c
deleted file mode 100644
index 9568643..0000000
--- a/libkc3_window/sdl2/disabled/sdl2_sprite.c
+++ /dev/null
@@ -1,369 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "sdl2_sprite.h"
-
-void sdl2_sprite_bind (const s_sdl2_sprite *sprite, uw frame)
-{
- assert(sprite);
- assert(frame < sprite->frame_count);
- frame %= sprite->frame_count;
- assert(glGetError() == GL_NO_ERROR);
- glBindTexture(GL_TEXTURE_2D, sprite->texture[frame]);
- assert(glGetError() == GL_NO_ERROR);
-}
-
-void sdl2_sprite_clean (s_sdl2_sprite *sprite)
-{
- assert(sprite);
- str_clean(&sprite->path);
- str_clean(&sprite->real_path);
- glDeleteTextures(sprite->frame_count, sprite->texture);
- free(sprite->texture);
-}
-
-static bool png_info_to_gl_info (s32 png_color_type,
- s32 png_bit_depth,
- GLenum *gl_format,
- GLint *gl_internal_format,
- GLenum *gl_type,
- u8 *components)
-{
- switch (png_bit_depth) {
- case 8: *gl_type = GL_UNSIGNED_BYTE; break;
- case 16: *gl_type = GL_UNSIGNED_SHORT; break;
- default: *gl_type = 0; return false;
- }
- switch (png_color_type) {
- case PNG_COLOR_TYPE_GRAY:
- *components = 1;
- *gl_format = GL_RED;
- switch (png_bit_depth) {
- case 8: *gl_internal_format = GL_RED; break;
- case 16: *gl_internal_format = GL_RED; break;
- default: *gl_internal_format = 0; return false;
- }
- break;
- case PNG_COLOR_TYPE_GRAY_ALPHA:
- *components = 2;
- *gl_format = GL_RG;
- switch (png_bit_depth) {
- case 8: *gl_internal_format = GL_RG; break;
- case 16: *gl_internal_format = GL_RG; break;
- default: *gl_internal_format = 0; return false;
- }
- break;
- case PNG_COLOR_TYPE_RGB:
- *components = 3;
- *gl_format = GL_RGB;
- switch (png_bit_depth) {
- case 8: *gl_internal_format = GL_RGB; break;
- case 16: *gl_internal_format = GL_RGB; break;
- default: *gl_internal_format = 0; return false;
- }
- break;
- case PNG_COLOR_TYPE_RGBA:
- *components = 4;
- *gl_format = GL_RGBA;
- switch (png_bit_depth) {
- case 8: *gl_internal_format = GL_RGBA8; break;
- case 16: *gl_internal_format = GL_RGBA16; break;
- default: *gl_internal_format = 0; return false;
- }
- break;
- default:
- *components = 0;
- *gl_format = 0;
- *gl_internal_format = 0;
- return false;
- }
- return true;
-}
-
-s_sdl2_sprite * sdl2_sprite_init (s_sdl2_sprite *sprite,
- const s8 *path,
- uw dim_x, uw dim_y,
- uw frame_count)
-{
- u8 *data;
- FILE *fp;
- GLenum gl_format;
- GLint gl_internal_format;
- GLenum gl_type;
- uw i;
- s32 png_bit_depth;
- s32 png_color_type;
- u8 png_components;
- png_bytep png_data;
- u32 png_h;
- u8 png_header[8]; // maximum size is 8
- png_infop png_info;
- uw png_pixel_size;
- png_structp png_read;
- png_bytep *png_row;
- u32 png_w;
- u8 *sprite_data;
- uw sprite_stride;
- uw x;
- uw y;
- uw v;
- assert(sprite);
- assert(path);
- assert(dim_x);
- assert(dim_y);
- assert(glGetError() == GL_NO_ERROR);
- sprite->frame_count = (frame_count > 0) ? frame_count :
- (dim_x * dim_y);
- str_init_copy_1(&sprite->path, path);
- if (! file_search(&sprite->path, sym_1("r"), &sprite->real_path)) {
- err_write_1("sdl2_sprite_init: file not found: ");
- err_puts(path);
- str_clean(&sprite->path);
- return NULL;
- }
- fp = fopen(sprite->real_path.ptr.ps8, "rb");
- if (! fp) {
- err_write_1("sdl2_sprite_init: fopen: ");
- err_puts(sprite->real_path.ptr.ps8);
- str_clean(&sprite->path);
- str_clean(&sprite->real_path);
- return NULL;
- }
- if (fread(png_header, 1, sizeof(png_header), fp) !=
- sizeof(png_header)) {
- err_write_1("sdl2_sprite_init: fread: ");
- err_puts(sprite->real_path.ptr.ps8);
- fclose(fp);
- str_clean(&sprite->path);
- str_clean(&sprite->real_path);
- return NULL;
- }
- if (png_sig_cmp(png_header, 0, sizeof(png_header))) {
- err_write_1("sdl2_sprite_init: not a png: ");
- err_puts(sprite->real_path.ptr.ps8);
- fclose(fp);
- str_clean(&sprite->path);
- str_clean(&sprite->real_path);
- return NULL;
- }
- png_read = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL,
- NULL);
- if (! png_read) {
- err_write_1("sdl2_sprite_init: png_create_read_struct: ");
- err_puts(sprite->real_path.ptr.ps8);
- fclose(fp);
- str_clean(&sprite->path);
- str_clean(&sprite->real_path);
- return NULL;
- }
- png_info = png_create_info_struct(png_read);
- if (! png_info) {
- err_write_1("sdl2_sprite_init: png_create_info_struct: ");
- err_puts(sprite->real_path.ptr.ps8);
- png_destroy_read_struct(&png_read, NULL, NULL);
- fclose(fp);
- str_clean(&sprite->path);
- str_clean(&sprite->real_path);
- return NULL;
- }
- gl_internal_format = 0;
- gl_format = 0;
- gl_type = 0;
- png_components = 0;
- if (setjmp(png_jmpbuf(png_read))) {
- png_destroy_read_struct(&png_read, &png_info, NULL);
- fclose(fp);
- str_clean(&sprite->path);
- str_clean(&sprite->real_path);
- return NULL;
- }
- png_set_sig_bytes(png_read, sizeof(png_header));
- png_init_io(png_read, fp);
- png_read_info(png_read, png_info);
- png_get_IHDR(png_read, png_info, &png_w, &png_h,
- &png_bit_depth, &png_color_type,
- NULL, NULL, NULL);
- if (png_color_type == PNG_COLOR_TYPE_PALETTE)
- png_set_palette_to_rgb(png_read);
- if (! png_info_to_gl_info(png_color_type, png_bit_depth, &gl_format,
- &gl_internal_format, &gl_type,
- &png_components)) {
- if (! gl_format || ! png_components) {
- err_write_1("sdl2_sprite_init: unknown PNG color type ");
- err_inspect_s32(&png_color_type);
- err_write_1(": ");
- err_puts(sprite->real_path.ptr.ps8);
- }
- if (! gl_internal_format) {
- err_write_1("sdl2_sprite_init: unknown OpenGL internal format: ");
- err_puts(sprite->real_path.ptr.ps8);
- }
- if (! gl_type) {
- err_write_1("sdl2_sprite_init: unknown OpenGL type: ");
- err_puts(sprite->real_path.ptr.ps8);
- }
- png_destroy_read_struct(&png_read, &png_info, NULL);
- fclose(fp);
- str_clean(&sprite->path);
- str_clean(&sprite->real_path);
- return NULL;
- }
- png_pixel_size = (png_bit_depth / 8) * png_components;
- if (! png_pixel_size)
- png_error(png_read, "unknown png pixel size");
- if (png_h > PNG_SIZE_MAX / (png_w * png_pixel_size))
- png_error(png_read, "image_data buffer would be too large");
- png_data = png_malloc(png_read, png_h * png_w * png_pixel_size);
- png_row = png_malloc(png_read, png_h * sizeof(png_bytep));
- i = 0;
- while (i < png_h) {
- png_row[i] = png_data + i * png_w * png_pixel_size;
- i++;
- }
- if (png_bit_depth < 8)
- png_set_packing(png_read);
- png_read_image(png_read, png_row);
- png_destroy_read_struct(&png_read, &png_info, NULL);
- fclose(fp);
- sprite->total_w = png_w;
- sprite->total_h = png_h;
- sprite->dim_x = dim_x;
- sprite->dim_y = dim_y;
- sprite->w = sprite->total_w / dim_x;
- sprite->h = sprite->total_h / dim_y;
- sprite->texture = calloc(sprite->frame_count, sizeof(GLuint));
- if (! sprite->texture) {
- err_puts("sdl2_sprite_init: sprite->texture:"
- " failed to allocate memory");
- str_clean(&sprite->path);
- str_clean(&sprite->real_path);
- return NULL;
- }
- glGenTextures(sprite->frame_count, sprite->texture);
- GLenum gl_error = glGetError();
- if (gl_error != GL_NO_ERROR) {
- err_write_1("sdl2_sprite_init: ");
- err_inspect_str(&sprite->real_path);
- err_write_1(": glGenTextures: ");
- err_puts((const s8 *) gluErrorString(gl_error));
- free(sprite->texture);
- str_clean(&sprite->path);
- str_clean(&sprite->real_path);
- return NULL;
- }
- sprite_stride = sprite->w * png_pixel_size;
- data = malloc(sprite->h * sprite_stride);
- if (! data) {
- err_write_1("sdl2_sprite_init: failed to allocate memory: ");
- err_puts(sprite->real_path.ptr.ps8);
- free(sprite->texture);
- str_clean(&sprite->path);
- str_clean(&sprite->real_path);
- return NULL;
- }
- i = 0;
- y = 0;
- while (i < sprite->frame_count && y < dim_y) {
- x = 0;
- while (i < sprite->frame_count && x < dim_x) {
- sprite_data = data + sprite_stride * sprite->h;
- v = 0;
- while (v < sprite->h) {
- sprite_data -= sprite_stride;
- memcpy(sprite_data,
- png_row[y * sprite->h + v] + x * sprite_stride,
- sprite_stride);
- v++;
- }
- glBindTexture(GL_TEXTURE_2D, sprite->texture[i]);
- gl_error = glGetError();
- if (gl_error != GL_NO_ERROR) {
- err_write_1("sdl2_sprite_init: ");
- err_inspect_str(&sprite->real_path);
- err_write_1(": glBindTexture: ");
- err_puts((const s8 *) gluErrorString(gl_error));
- return NULL;
- }
- 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_LINEAR_MIPMAP_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl_error = glGetError();
- if (gl_error != GL_NO_ERROR) {
- err_write_1("sdl2_sprite_init: ");
- err_inspect_str(&sprite->real_path);
- err_write_1(": glTexParameteri: ");
- err_puts((const s8 *) gluErrorString(gl_error));
- return NULL;
- }
- glTexImage2D(GL_TEXTURE_2D, 0, gl_format, sprite->w, sprite->h,
- 0, gl_format, gl_type, data);
- //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sprite->w, sprite->h,
- // 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
- gl_error = glGetError();
- if (gl_error != GL_NO_ERROR) {
- err_write_1("sdl2_sprite_init: ");
- err_inspect_str(&sprite->real_path);
- err_write_1(": glTexImage2D: ");
- err_puts((const s8 *) gluErrorString(gl_error));
- return NULL;
- }
- glGenerateMipmap(GL_TEXTURE_2D);
- assert(glGetError() == GL_NO_ERROR);
- i++;
- x++;
- }
- y++;
- }
- glBindTexture(GL_TEXTURE_2D, 0);
- free(data);
- free(png_data);
- free(png_row);
- return sprite;
-}
-
-void sdl2_sprite_render (const s_sdl2_sprite *sprite, uw frame)
-{
- assert(sprite);
- assert(frame < sprite->frame_count);
- frame %= sprite->frame_count;
- glColor4f(1, 1, 1, 1);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glDisable(GL_CULL_FACE);
- glEnable(GL_TEXTURE_2D);
- glBindTexture(GL_TEXTURE_2D, sprite->texture[frame]);
- glBegin(GL_QUADS); {
- glTexCoord2f(0, 1);
- glVertex2d(0, sprite->h);
- glTexCoord2f(0, 0);
- glVertex2i(0, 0);
- glTexCoord2f(1, 0);
- glVertex2i(sprite->w, 0);
- glTexCoord2f(1, 1);
- glVertex2d(sprite->w, sprite->h);
- } glEnd();
- glBindTexture(GL_TEXTURE_2D, 0);
- glDisable(GL_TEXTURE_2D);
- /*
- glBegin(GL_LINE_LOOP); {
- glVertex2d(0, sprite->h);
- glVertex2i(0, 0);
- glVertex2i(sprite->w, 0);
- glVertex2d(sprite->w, sprite->h);
- } glEnd();
- */
-}
diff --git a/libkc3_window/sdl2/disabled/sdl2_sprite.h b/libkc3_window/sdl2/disabled/sdl2_sprite.h
deleted file mode 100644
index 720d3f9..0000000
--- a/libkc3_window/sdl2/disabled/sdl2_sprite.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 SDL2_SPRITE_H
-#define SDL2_SPRITE_H
-
-#include "types.h"
-
-/* stack allocation compatible functions */
-void sdl2_sprite_clean (s_sdl2_sprite *sprite);
-s_sdl2_sprite * sdl2_sprite_init (s_sdl2_sprite *sprite,
- const s8 *path,
- uw dim_x, uw dim_y,
- uw frame_count);
-
-/* operations */
-void sdl2_sprite_bind (const s_sdl2_sprite *sprite, uw frame);
-void sdl2_sprite_render (const s_sdl2_sprite *sprite, uw frame);
-
-#endif /* CAIRO_SPRITE_H */
diff --git a/libkc3_window/sdl2/dmat3.h b/libkc3_window/sdl2/dmat3.h
deleted file mode 100644
index 2e3a3c4..0000000
--- a/libkc3_window/sdl2/dmat3.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 DMAT3_H
-#define DMAT3_H
-
-#include "types.h"
-
-/* Stack-allocation compatible functions. */
-s_dmat3 * dmat3_init_copy (s_dmat3 *m, const s_dmat3 *src);
-s_dmat3 * dmat3_init_identity (s_dmat3 *m);
-s_dmat3 * dmat3_init_matrix_mult (s_dmat3 *m, const s_dmat3 *a,
- const s_dmat3 *b);
-
-/* Heap-allocation functions, call dmat3_delete after use. */
-void dmat3_delete (s_dmat3 *m);
-s_dmat3 * dmat3_new_copy (const s_dmat3 *src);
-s_dmat3 * dmat3_new_identity (void);
-s_dmat3 * dmat3_new_matrix_mult (const s_dmat3 *a, const s_dmat3 *b);
-
-/* Operators. */
-s_dmat3 * dmat3_rotate (s_dmat3 *m, f64 rad);
-s_dmat3 * dmat3_scale (s_dmat3 *m, f64 x, f64 y);
-s_dmat3 * dmat3_translate (s_dmat3 *m, f64 x, f64 y);
-
-#endif /* DMAT3_H */
diff --git a/libkc3_window/sdl2/dmat4.c b/libkc3_window/sdl2/dmat4.c
deleted file mode 100644
index 674f3f4..0000000
--- a/libkc3_window/sdl2/dmat4.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "dmat4.h"
-#include "dvec3.h"
-
-sw dmat4_buf_inspect (s_buf *buf, const s_dmat4 *matrix)
-{
- u8 i;
- u8 j;
- sw r;
- sw result = 0;
- assert(buf);
- assert(matrix);
- const f64 *m;
- if ((r = buf_write_1(buf, "(F64) {")) < 0)
- return r;
- result += r;
- m = &matrix->xx;
- i = 0;
- while (i < 4) {
- j = 0;
- while (j < 4) {
- if ((r = buf_inspect_f64(buf, m + j * 4 + i)) < 0)
- return r;
- result += r;
- if (i < 3 || j < 3) {
- if ((r = buf_write_1(buf, ",")) < 0)
- return r;
- result += r;
- if (j < 3) {
- if ((r = buf_write_1(buf, " ")) < 0)
- return r;
- result += r;
- }
- }
- j++;
- }
- if (i < 3) {
- if ((r = buf_write_1(buf, "\n ")) < 0)
- return r;
- result += r;
- }
- i++;
- }
- if ((r = buf_write_1(buf, "}\n")) < 0)
- return r;
- result += r;
- return result;
-}
-
-s_dmat4 * dmat4_init_copy (s_dmat4 *m, const s_dmat4 *src)
-{
- assert(m);
- assert(src);
- *m = *src;
- return m;
-}
-
-s_dmat4 * dmat4_init_product (s_dmat4 *m, const s_dmat4 *a,
- const s_dmat4 *b)
-{
- assert(m);
- assert(a);
- assert(b);
- m->xx = a->xx * b->xx + a->xy * b->yx + a->xz * b->zx + a->xt * b->tx;
- m->xy = a->xx * b->xy + a->xy * b->yy + a->xz * b->zy + a->xt * b->ty;
- m->xz = a->xx * b->xz + a->xy * b->yz + a->xz * b->zz + a->xt * b->tz;
- m->xt = a->xx * b->xt + a->xy * b->yt + a->xz * b->zt + a->xt * b->tt;
- m->yx = a->yx * b->xx + a->yy * b->yx + a->yz * b->zx + a->yt * b->tx;
- m->yy = a->yx * b->xy + a->yy * b->yy + a->yz * b->zy + a->yt * b->ty;
- m->yz = a->yx * b->xz + a->yy * b->yz + a->yz * b->zz + a->yt * b->tz;
- m->yt = a->yx * b->xt + a->yy * b->yt + a->yz * b->zt + a->yt * b->tt;
- m->zx = a->zx * b->xx + a->zy * b->yx + a->zz * b->zx + a->zt * b->tx;
- m->zy = a->zx * b->xy + a->zy * b->yy + a->zz * b->zy + a->zt * b->ty;
- m->zz = a->zx * b->xz + a->zy * b->yz + a->zz * b->zz + a->zt * b->tz;
- m->zt = a->zx * b->xt + a->zy * b->yt + a->zz * b->zt + a->zt * b->tt;
- m->tx = a->tx * b->xx + a->ty * b->yx + a->tz * b->zx + a->tt * b->tx;
- m->ty = a->tx * b->xy + a->ty * b->yy + a->tz * b->zy + a->tt * b->ty;
- m->tz = a->tx * b->xz + a->ty * b->yz + a->tz * b->zz + a->tt * b->tz;
- m->tt = a->tx * b->xt + a->ty * b->yt + a->tz * b->zt + a->tt * b->tt;
- return m;
-}
-
-s_dmat4 * dmat4_init_identity (s_dmat4 *m)
-{
- assert(m);
- m->xx = 1.0; m->xy = 0.0; m->xz = 0.0; m->xt = 0.0;
- m->yx = 0.0; m->yy = 1.0; m->yz = 0.0; m->yt = 0.0;
- m->zx = 0.0; m->zy = 0.0; m->zz = 1.0; m->zt = 0.0;
- m->tx = 0.0; m->ty = 0.0; m->tz = 0.0; m->tt = 1.0;
- return m;
-}
-
-s_dmat4 * dmat4_init_scale (s_dmat4 *m, f64 x, f64 y, f64 z)
-{
- assert(m);
- m->xx = x; m->xy = 0.0; m->xz = 0.0; m->xt = 0.0;
- m->yx = 0.0; m->yy = y; m->yz = 0.0; m->yt = 0.0;
- m->zx = 0.0; m->zy = 0.0; m->zz = z; m->zt = 0.0;
- m->tx = 0.0; m->ty = 0.0; m->tz = 0.0; m->tt = 1.0;
- return m;
-}
-
-s_dmat4 * dmat4_init_zero (s_dmat4 *m)
-{
- assert(m);
- m->xx = 0.0; m->xy = 0.0; m->xz = 0.0; m->xt = 0.0;
- m->yx = 0.0; m->yy = 0.0; m->yz = 0.0; m->yt = 0.0;
- m->zx = 0.0; m->zy = 0.0; m->zz = 0.0; m->zt = 0.0;
- m->tx = 0.0; m->ty = 0.0; m->tz = 0.0; m->tt = 0.0;
- return m;
-}
-
-void dmat4_delete (s_dmat4 *m)
-{
- free(m);
-}
-
-s_dmat4 * dmat4_new_copy (const s_dmat4 *src)
-{
- s_dmat4 *m;
- m = calloc(1, sizeof(s_dmat4));
- if (! m) {
- err_puts("dmat4_new: failed to allocate memory");
- return NULL;
- }
- *m = *src;
- return m;
-}
-
-s_dmat4 * dmat4_new_product (const s_dmat4 *a, const s_dmat4 *b)
-{
- s_dmat4 *m;
- assert(a);
- assert(b);
- m = calloc(1, sizeof(s_dmat4));
- if (! m) {
- err_puts("dmat4_new: failed to allocate memory");
- return NULL;
- }
- dmat4_init_product(m, a, b);
- return m;
-}
-
-s_dmat4 * dmat4_new_zero (void)
-{
- s_dmat4 *m;
- m = calloc(1, sizeof(s_dmat4));
- if (! m) {
- err_puts("dmat4_new: failed to allocate memory");
- return NULL;
- }
- dmat4_init_zero(m);
- return m;
-}
-
-s_dmat4 * dmat4_ortho (s_dmat4 *m, f64 x1, f64 x2, f64 y1, f64 y2,
- f64 clip_z_near, f64 clip_z_far)
-{
- f64 dx;
- f64 dy;
- f64 dz;
- s_dmat4 ortho;
- assert(m);
- dx = x2 - x1;
- dy = y2 - y1;
- dz = clip_z_far - clip_z_near;
- dmat4_init_zero(&ortho);
- ortho.xx = 2.0 / dx;
- ortho.yy = 2.0 / dy;
- ortho.zz = -2.0 / dz;
- ortho.tx = - (x1 + x2) / dx;
- ortho.ty = - (y1 + y2) / dy;
- ortho.tz = - (clip_z_near + clip_z_far) / dz;
- ortho.tt = 1.0;
- dmat4_product(&ortho, m);
- *m = ortho;
- return m;
-}
-
-s_dmat4 * dmat4_perspective (s_dmat4 *m, f64 fov_y, f64 aspect_ratio,
- f64 z_near, f64 z_far)
-{
- f64 dz;
- s_dmat4 perspective;
- f64 f;
- f64 fov_y_2;
- fov_y_2 = fov_y / 2.0;
- f = cos(fov_y_2) / sin(fov_y_2);
- dz = z_near - z_far;
- dmat4_init_zero(&perspective);
- perspective.xx = f / aspect_ratio;
- perspective.yy = f;
- perspective.zz = (z_near + z_far) / dz;
- perspective.zt = -1.0;
- perspective.tz = 2.0 * z_near * z_far / dz;
- dmat4_product(&perspective, m);
- *m = perspective;
- return m;
-}
-
-s_dmat4 * dmat4_product (s_dmat4 *m, const s_dmat4 *a)
-{
- s_dmat4 tmp;
- dmat4_init_product(&tmp, m, a);
- *m = tmp;
- return m;
-}
-
-s_dmat4 * dmat4_rotate_axis (s_dmat4 *m, f64 rad,
- const s_dvec3 *axis)
-{
- s_dvec3 a;
- f64 angle;
- f64 one_minus_x;
- f64 x;
- f64 y;
- dvec3_init_normalize(&a, axis);
- angle = -rad;
- x = cos(angle);
- one_minus_x = 1.0 - x;
- y = sin(angle);
- s_dmat4 r = { x + a.x * a.x * one_minus_x,
- a.x * a.y * one_minus_x - a.z * y,
- a.x * a.z * one_minus_x + a.y * y,
- 0.0,
- a.x * a.y * one_minus_x + a.z * y,
- x + a.y * a.y * one_minus_x,
- a.y * a.z * one_minus_x - a.x * y,
- 0.0,
- a.x * a.z * one_minus_x - a.y * y,
- a.y * a.z * one_minus_x + a.x * y,
- x + a.z * a.z * one_minus_x,
- 0.0,
- 0.0, 0.0, 0.0, 1.0 };
- dmat4_product(&r, m);
- *m = r;
- return m;
-}
-
-s_dmat4 * dmat4_scale (s_dmat4 *m, f64 x, f64 y, f64 z)
-{
- s_dmat4 s;
- dmat4_init_zero(&s);
- s.xx = x;
- s.yy = y;
- s.zz = z;
- s.tt = 1.0;
- dmat4_product(&s, m);
- *m = s;
- return m;
-}
-
-s_dmat4 * dmat4_translate (s_dmat4 *m, f64 x, f64 y, f64 z)
-{
- s_dmat4 s;
- dmat4_init_identity(&s);
- s.tx = x;
- s.ty = y;
- s.tz = z;
- dmat4_product(&s, m);
- *m = s;
- return m;
-}
diff --git a/libkc3_window/sdl2/dmat4.h b/libkc3_window/sdl2/dmat4.h
deleted file mode 100644
index 98659cf..0000000
--- a/libkc3_window/sdl2/dmat4.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 DMAT4_H
-#define DMAT4_H
-
-#include "types.h"
-
-/* Stack-allocation compatible functions. */
-s_dmat4 * dmat4_init_copy (s_dmat4 *m, const s_dmat4 *src);
-s_dmat4 * dmat4_init_identity (s_dmat4 *m);
-s_dmat4 * dmat4_init_product (s_dmat4 *m, const s_dmat4 *a,
- const s_dmat4 *b);
-s_dmat4 * dmat4_init_zero (s_dmat4 *m);
-
-/* Heap-allocation functions, call dmat4_delete after use. */
-void dmat4_delete (s_dmat4 *m);
-s_dmat4 * dmat4_new_copy (const s_dmat4 *src);
-s_dmat4 * dmat4_new_identity (void);
-s_dmat4 * dmat4_new_matrix_mult (const s_dmat4 *a, const s_dmat4 *b);
-s_dmat4 * dmat4_new_zero (void);
-
-/* Operators. */
-s_dmat4 * dmat4_ortho (s_dmat4 *m, f64 x1, f64 x2, f64 y1, f64 y2,
- f64 clip_z_near, f64 clip_z_far);
-s_dmat4 * dmat4_perspective (s_dmat4 *m, f64 fov_y, f64 aspect_ratio,
- f64 clip_z_near, f64 clip_z_far);
-s_dmat4 * dmat4_product (s_dmat4 *m, const s_dmat4 *a);
-s_dmat4 * dmat4_rotate_axis (s_dmat4 *m, f64 rad,
- const s_dvec3 *axis);
-s_dmat4 * dmat4_scale (s_dmat4 *m, f64 x, f64 y, f64 z);
-s_dmat4 * dmat4_translate (s_dmat4 *m, f64 x, f64 y, f64 z);
-
-#endif /* DMAT4_H */
diff --git a/libkc3_window/sdl2/dvec2.c b/libkc3_window/sdl2/dvec2.c
deleted file mode 100644
index bfefca2..0000000
--- a/libkc3_window/sdl2/dvec2.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "dvec2.h"
-
-s_dvec2 * dvec2_init (s_dvec2 *p, f64 x, f64 y)
-{
- assert(p);
- p->x = x;
- p->y = y;
- return p;
-}
-
-s_dvec2 * dvec2_init_copy (s_dvec2 *p, const s_dvec2 *src)
-{
- assert(p);
- assert(src);
- p->x = src->x;
- p->y = src->y;
- return p;
-}
-
-s_dvec2 * dvec2_init_product (s_dvec2 *p, const s_dmat3 *m,
- const s_dvec2 *s)
-{
- assert(p);
- assert(m);
- assert(s);
- p->x = s->x * m->xx + s->y * m->xy + m->xz;
- p->y = s->x * m->yx + s->y * m->yy + m->yz;
- return p;
-}
-
-s_dvec2 * dvec2_init_zero (s_dvec2 *p)
-{
- assert(p);
- p->x = 0.0;
- p->y = 0.0;
- return p;
-}
-
-void dvec2_delete (s_dvec2 *p)
-{
- free(p);
-}
-
-s_dvec2 * dvec2_new (f64 x, f64 y)
-{
- s_dvec2 *p;
- p = calloc(1, sizeof(s_dvec2));
- if (! p) {
- err_puts("dvec2_new: failed to allocate memory");
- return NULL;
- }
- dvec2_init(p, x, y);
- return p;
-}
-
-s_dvec2 * dvec2_new_copy (const s_dvec2 *src)
-{
- s_dvec2 *p;
- p = calloc(1, sizeof(s_dvec2));
- if (! p) {
- err_puts("dvec2_new: failed to allocate memory");
- return NULL;
- }
- dvec2_init_copy(p, src);
- return p;
-}
-
-s_dvec2 * dvec2_new_zero (void)
-{
- s_dvec2 *p;
- p = calloc(1, sizeof(s_dvec2));
- if (! p) {
- err_puts("dvec2_new: failed to allocate memory");
- return NULL;
- }
- dvec2_init_zero(p);
- return p;
-}
diff --git a/libkc3_window/sdl2/dvec2.h b/libkc3_window/sdl2/dvec2.h
deleted file mode 100644
index 13c5e85..0000000
--- a/libkc3_window/sdl2/dvec2.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 DVEC2_H
-#define DVEC2_H
-
-#include "types.h"
-
-/* Stack-allocation compatible functions. */
-s_dvec2 * dvec2_init (s_dvec2 *p, f64 x, f64 y);
-s_dvec2 * dvec2_init_copy (s_dvec2 *p, const s_dvec2 *src);
-s_dvec2 * dvec2_init_product (s_dvec2 *p, const s_dmat3 *m,
- const s_dvec2 *s);
-s_dvec2 * dvec2_init_zero (s_dvec2 *p);
-
-/* Heap-allocation functions, call dvec2_delete after use. */
-void dvec2_delete (s_dvec2 *p);
-s_dvec2 * dvec2_new (f64 x, f64 y);
-s_dvec2 * dvec2_new_copy (const s_dvec2 *src);
-s_dvec2 * dvec2_new_product (const s_dmat3 *m, const s_dvec2 *s);
-s_dvec2 * dvec2_new_zero (void);
-
-#endif /* DVEC2_H */
diff --git a/libkc3_window/sdl2/dvec3.c b/libkc3_window/sdl2/dvec3.c
deleted file mode 100644
index 15be8f5..0000000
--- a/libkc3_window/sdl2/dvec3.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "dvec3.h"
-
-s_dvec3 * dvec3_init (s_dvec3 *p, f64 x, f64 y, f64 z)
-{
- assert(p);
- p->x = x;
- p->y = y;
- p->z = z;
- return p;
-}
-
-s_dvec3 * dvec3_init_copy (s_dvec3 *p, const s_dvec3 *src)
-{
- assert(p);
- assert(src);
- p->x = src->x;
- p->y = src->y;
- p->z = src->z;
- return p;
-}
-
-s_dvec3 * dvec3_init_normalize (s_dvec3 *p, const s_dvec3 *src)
-{
- f64 r;
- assert(p);
- assert(src);
- r = 1.0 / dvec3_norm(src);
- p->x = src->x * r;
- p->y = src->y * r;
- p->z = src->z * r;
- return p;
-}
-
-s_dvec3 * dvec3_init_product (s_dvec3 *p, const s_dmat4 *m,
- const s_dvec3 *s)
-{
- assert(p);
- assert(m);
- assert(s);
- p->x = s->x * m->xx + s->y * m->xy + s->z * m->xz + m->xt;
- p->y = s->x * m->yx + s->y * m->yy + s->z * m->yz + m->yt;
- p->z = s->x * m->zx + s->y * m->zy + s->z * m->zz + m->zt;
- return p;
-}
-
-s_dvec3 * dvec3_init_zero (s_dvec3 *p)
-{
- assert(p);
- p->x = 0.0;
- p->y = 0.0;
- p->z = 0.0;
- return p;
-}
-
-void dvec3_delete (s_dvec3 *p)
-{
- free(p);
-}
-
-s_dvec3 * dvec3_new (f64 x, f64 y, f64 z)
-{
- s_dvec3 *p;
- p = calloc(1, sizeof(s_dvec3));
- if (! p) {
- err_puts("dvec3_new: failed to allocate memory");
- return NULL;
- }
- dvec3_init(p, x, y, z);
- return p;
-}
-
-s_dvec3 * dvec3_new_copy (const s_dvec3 *src)
-{
- s_dvec3 *p;
- p = calloc(1, sizeof(s_dvec3));
- if (! p) {
- err_puts("dvec3_new: failed to allocate memory");
- return NULL;
- }
- dvec3_init_copy(p, src);
- return p;
-}
-
-s_dvec3 * dvec3_new_product (const s_dmat4 *m, const s_dvec3 *s)
-{
- s_dvec3 *p;
- assert(m);
- assert(s);
- p = calloc(1, sizeof(s_dvec3));
- if (! p) {
- err_puts("dvec3_new: failed to allocate memory");
- return NULL;
- }
- dvec3_init_product(p, m, s);
- return p;
-}
-
-s_dvec3 * dvec3_new_zero (void)
-{
- s_dvec3 *p;
- p = calloc(1, sizeof(s_dvec3));
- if (! p) {
- err_puts("dvec3_new: failed to allocate memory");
- return NULL;
- }
- dvec3_init_zero(p);
- return p;
-}
-
-f64 dvec3_norm (const s_dvec3 *p)
-{
- assert(p);
- return sqrt(p->x * p->x + p->y * p->y + p->z * p->z);
-}
-
-void dvec3_normalize (s_dvec3 *p)
-{
- f64 inv_norm;
- assert(p);
- inv_norm = 1.0 / dvec3_norm(p);
- p->x *= inv_norm;
- p->y *= inv_norm;
- p->z *= inv_norm;
-}
-
-void dvec3_transform (s_dvec3 *p, const s_dmat4 *matrix)
-{
- s_dvec3 tmp;
- assert(p);
- assert(matrix);
- dvec3_init_product(&tmp, matrix, p);
- *p = tmp;
-}
diff --git a/libkc3_window/sdl2/dvec3.h b/libkc3_window/sdl2/dvec3.h
deleted file mode 100644
index 13f3d30..0000000
--- a/libkc3_window/sdl2/dvec3.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 DVEC3_H
-#define DVEC3_H
-
-#include "types.h"
-
-/* Stack-allocation compatible functions. */
-s_dvec3 * dvec3_init (s_dvec3 *p, f64 x, f64 y, f64 z);
-s_dvec3 * dvec3_init_copy (s_dvec3 *p, const s_dvec3 *src);
-s_dvec3 * dvec3_init_normalize (s_dvec3 *p, const s_dvec3 *src);
-s_dvec3 * dvec3_init_product (s_dvec3 *p, const s_dmat4 *m,
- const s_dvec3 *s);
-s_dvec3 * dvec3_init_zero (s_dvec3 *p);
-
-/* Heap-allocation functions, call dvec3_delete after use. */
-void dvec3_delete (s_dvec3 *p);
-s_dvec3 * dvec3_new (f64 x, f64 y, f64 z);
-s_dvec3 * dvec3_new_copy (const s_dvec3 *src);
-s_dvec3 * dvec3_new_product (const s_dmat4 *m,
- const s_dvec3 *s);
-s_dvec3 * dvec3_new_zero (void);
-
-/* Operators. */
-void dvec3_normalize (s_dvec3 *p);
-void dvec3_transform (s_dvec3 *p, const s_dmat4 *matrix);
-
-/* Observers. */
-f64 dvec3_norm (const s_dvec3 *p);
-
-#endif /* DVEC3_H */
diff --git a/libkc3_window/sdl2/gl_camera.c b/libkc3_window/sdl2/gl_camera.c
deleted file mode 100644
index e85b1bd..0000000
--- a/libkc3_window/sdl2/gl_camera.c
+++ /dev/null
@@ -1,321 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "gl_camera.h"
-#include "mat4.h"
-
-static const char * g_gl_camera_vertex_shader_src =
- "#version 330 core\n"
- "layout (location = 0) in vec3 iPos;\n"
- "layout (location = 1) in vec3 iNormal;\n"
- "layout (location = 2) in vec2 iTexCoord;\n"
- "out vec3 ioNormal;\n"
- "out vec3 ioPos;\n"
- "out vec2 ioTexCoord;\n"
- "uniform mat4 uProjectionMatrix;\n"
- "uniform mat4 uViewMatrix;\n"
- "uniform mat4 uModelMatrix;\n"
- "\n"
- "void main() {\n"
- " gl_Position = vec4(uProjectionMatrix * uViewMatrix *\n"
- " uModelMatrix * vec4(iPos, 1.0));\n"
- " ioNormal = vec3(uViewMatrix * uModelMatrix * vec4(iNormal, 1.0));\n"
- " ioPos = (uViewMatrix * uModelMatrix * vec4(iPos, 1.0)).xyz;\n"
- " ioTexCoord = iTexCoord;\n"
- "}\n";
-
-static const char * g_gl_camera_fragment_shader_src =
- "#version 330 core\n"
- "const float PI = 3.141592653;\n"
- "in vec3 ioNormal;\n"
- "in vec3 ioPos;\n"
- "in vec2 ioTexCoord;\n"
- "out vec4 oColor;\n"
- "uniform bool uEnableTex2D;\n"
- "uniform sampler2D uTex2D;\n"
- "uniform int uLightCount;\n"
- "uniform vec3 uLightPos[16]; // Light position in cam. coords.\n"
- "uniform vec3 uLightColor[16];\n"
- "uniform struct MaterialInfo {\n"
- " float Rough; // Roughness\n"
- " bool Metal; // Metallic (true) or dielectric (false)\n"
- " vec4 Color; // Diffuse color for dielectrics, f0 for metallic\n"
- "} uMaterial;\n"
- "float ggxDistribution (float nDotH) {\n"
- " float alpha2 = uMaterial.Rough * uMaterial.Rough *\n"
- " uMaterial.Rough * uMaterial.Rough;\n"
- " float d = (nDotH * nDotH) * (alpha2 - 1) + 1;\n"
- " return alpha2 / (PI * d * d);\n"
- "}\n"
- "float geomSmith( float dotProd ) {\n"
- " float k = (uMaterial.Rough + 1.0) * (uMaterial.Rough + 1.0) / 8.0;\n"
- " float denom = dotProd * (1 - k) + k;\n"
- " return 1.0 / denom;\n"
- "}\n"
- "vec4 schlickFresnel( float lDotH ) {\n"
- " vec4 f0 = vec4(0.04, 0.04, 0.04, 1.0);\n"
- " if( uMaterial.Metal ) {\n"
- " f0 = uMaterial.Color;\n"
- " }\n"
- " return f0 + (1 - f0) * pow(1.0 - lDotH, 5);\n"
- "}\n"
- "vec4 microfacetModel (int lightIdx, vec3 pos, vec3 n, vec4 color) {\n"
- " vec4 diffuseBrdf = vec4(0.0, 0.0, 0.0, 1.0); // Metallic\n"
- " if (! uMaterial.Metal) {\n"
- " diffuseBrdf = color;\n"
- " }\n"
- " vec3 l = vec3(0.0);\n"
- " vec3 lightI = uLightColor[lightIdx];\n"
- " l = uLightPos[lightIdx] - pos;\n"
- " float dist = length(l);\n"
- " l = normalize(l);\n"
- " lightI /= (dist * dist);\n"
- " vec3 v = normalize(-pos);\n"
- " vec3 h = normalize(v + l);\n"
- " float nDotH = dot(n, h);\n"
- " float lDotH = dot(l, h);\n"
- " float nDotL = max(dot(n, l), 0.0);\n"
- " float nDotV = dot(n, v);\n"
- " vec4 specBrdf = 0.25 * ggxDistribution(nDotH) *\n"
- " schlickFresnel(lDotH) * geomSmith(nDotL) * geomSmith(nDotV);\n"
- " return (diffuseBrdf + PI * specBrdf) * vec4(lightI, 1.0) * nDotL;\n"
- "}\n"
- "void main() {\n"
- " vec4 texColor = texture(uTex2D, ioTexCoord);\n"
- " if (uEnableTex2D) {\n"
- " oColor = texColor * uMaterial.Color;\n"
- " }\n"
- " else\n"
- " oColor = uMaterial.Color;\n"
- " vec4 sum = vec4(0);\n"
- " vec3 n = normalize(ioNormal);\n"
- " for (int i = 0; i < uLightCount; i++) {\n"
- " sum += microfacetModel(i, ioPos, n, oColor);\n"
- " }\n"
- " sum = pow(sum, vec4(1.0 / 2.2));\n"
- " oColor += sum;\n"
- "}\n";
-
-void gl_camera_bind_texture (s_gl_camera *camera, GLuint texture)
-{
- assert(camera);
- assert(glGetError() == GL_NO_ERROR);
- if (! texture) {
- glActiveTexture(GL_TEXTURE0);
- assert(glGetError() == GL_NO_ERROR);
- glBindTexture(GL_TEXTURE_2D, 0);
- assert(glGetError() == GL_NO_ERROR);
- glUniform1i(camera->gl_enable_tex2d_loc, 0);
- assert(glGetError() == GL_NO_ERROR);
- glUniform1i(camera->gl_tex2d_loc, 0);
- assert(glGetError() == GL_NO_ERROR);
- return;
- }
- glActiveTexture(GL_TEXTURE0);
- assert(glGetError() == GL_NO_ERROR);
- glBindTexture(GL_TEXTURE_2D, texture);
- assert(glGetError() == GL_NO_ERROR);
- glUniform1i(camera->gl_enable_tex2d_loc, 1);
- assert(glGetError() == GL_NO_ERROR);
- glUniform1i(camera->gl_tex2d_loc, 0);
- assert(glGetError() == GL_NO_ERROR);
-}
-
-void gl_camera_clean (s_gl_camera *camera)
-{
- assert(camera);
- glDeleteProgram(camera->gl_shader_program);
-}
-
-void gl_camera_material (s_gl_camera *camera, const s_gl_material *material)
-{
- assert(camera);
- assert(material);
- assert(glGetError() == GL_NO_ERROR);
- glUniform1f(camera->gl_material_rough_loc, material->roughness);
- assert(glGetError() == GL_NO_ERROR);
- glUniform1i(camera->gl_material_metal_loc, material->metal);
- assert(glGetError() == GL_NO_ERROR);
- glUniform4fv(camera->gl_material_color_loc, 1, &material->color.r);
- assert(glGetError() == GL_NO_ERROR);
-}
-
-void gl_camera_delete (s_gl_camera *camera)
-{
- gl_camera_clean(camera);
- free(camera);
-}
-
-s_gl_camera * gl_camera_init (s_gl_camera *camera, uw w, uw h)
-{
- GLuint fragment_shader;
- GLint success;
- GLuint vertex_shader;
- assert(camera);
- gl_camera_set_aspect_ratio(camera, w, h);
- camera->clip_z_far = 10.0f;
- camera->clip_z_near = 0.1f;
- camera->fov_y = 90.0f;
- camera->position.x = 0.0f;
- camera->position.y = 0.0f;
- camera->position.z = -10.0f;
- camera->rotation.x = M_PI / 2.0;
- camera->rotation.y = 0.0f;
- camera->rotation.z = 0.0f;
- camera->light_count = 1;
- camera->light_pos[0] = (s_vec3) {-100, 0, 0};
- camera->light_color[0] = (s_rgb) {1, 1, 1};
- vertex_shader = glCreateShader(GL_VERTEX_SHADER);
- glShaderSource(vertex_shader, 1, &g_gl_camera_vertex_shader_src,
- NULL);
- glCompileShader(vertex_shader);
- glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
- if (! success) {
- char info_log[512];
- glGetShaderInfoLog(vertex_shader, sizeof(info_log), NULL, info_log);
- err_write_1("gl_camera_init: shader compilation failed: ");
- err_puts(info_log);
- }
- fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
- glShaderSource(fragment_shader, 1, &g_gl_camera_fragment_shader_src,
- NULL);
- glCompileShader(fragment_shader);
- glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
- if (! success) {
- char info_log[512];
- glGetShaderInfoLog(fragment_shader, sizeof(info_log), NULL, info_log);
- err_write_1("gl_camera_init: shader compilation failed: ");
- err_puts(info_log);
- }
- camera->gl_shader_program = glCreateProgram();
- glAttachShader(camera->gl_shader_program, vertex_shader);
- glAttachShader(camera->gl_shader_program, fragment_shader);
- glLinkProgram(camera->gl_shader_program);
- glDeleteShader(vertex_shader);
- glDeleteShader(fragment_shader);
- camera->gl_projection_matrix_loc =
- glGetUniformLocation(camera->gl_shader_program,
- "uProjectionMatrix");
- camera->gl_view_matrix_loc =
- glGetUniformLocation(camera->gl_shader_program,
- "uViewMatrix");
- camera->gl_model_matrix_loc =
- glGetUniformLocation(camera->gl_shader_program,
- "uModelMatrix");
- camera->gl_enable_tex2d_loc =
- glGetUniformLocation(camera->gl_shader_program,
- "uEnableTex2D");
- camera->gl_tex2d_loc =
- glGetUniformLocation(camera->gl_shader_program,
- "uTex2D");
- camera->gl_light_pos_loc =
- glGetUniformLocation(camera->gl_shader_program,
- "uLightPos");
- camera->gl_light_color_loc =
- glGetUniformLocation(camera->gl_shader_program,
- "uLightColor");
- camera->gl_material_rough_loc =
- glGetUniformLocation(camera->gl_shader_program,
- "uMaterial.Rough");
- camera->gl_material_metal_loc =
- glGetUniformLocation(camera->gl_shader_program,
- "uMaterial.Metal");
- camera->gl_material_color_loc =
- glGetUniformLocation(camera->gl_shader_program,
- "uMaterial.Color");
- return camera;
-}
-
-s_gl_camera * gl_camera_new (uw w, uw h)
-{
- s_gl_camera *camera;
- camera = calloc(1, sizeof(s_gl_camera));
- if (! camera) {
- err_puts("gl_camera_new: failed to allocate memory");
- return NULL;
- }
- if (! gl_camera_init(camera, w, h)) {
- free(camera);
- return NULL;
- }
- return camera;
-}
-
-void gl_camera_render (s_gl_camera *camera)
-{
- s_mat4 matrix;
- const s_gl_material material = {0.1, false, {1, 1, 1, 1}};
- assert(camera);
- assert(glGetError() == GL_NO_ERROR);
- mat4_init_identity(&camera->projection_matrix);
- mat4_perspective(&camera->projection_matrix, camera->fov_y,
- camera->aspect_ratio, camera->clip_z_near,
- camera->clip_z_far);
- mat4_init_identity(&camera->view_matrix);
- mat4_translate(&camera->view_matrix, camera->position.x,
- camera->position.y, camera->position.z);
- mat4_rotate_axis(&camera->view_matrix, camera->rotation.x,
- &(s_vec3) { 1.0f, 0.0f, 0.0f });
- mat4_rotate_axis(&camera->view_matrix, camera->rotation.y,
- &(s_vec3) { 0.0f, 1.0f, 0.0f });
- mat4_rotate_axis(&camera->view_matrix, camera->rotation.z,
- &(s_vec3) { 0.0f, 0.0f, 1.0f });
- mat4_init_identity(&camera->model_matrix);
- mat4_init_copy(&matrix, &camera->view_matrix);
- for (int i = 0; i < camera->light_count; i++)
- mat4_mult_vec3(&matrix, camera->light_pos + i,
- camera->light_pos_cam + i);
- glUseProgram(camera->gl_shader_program);
- assert(glGetError() == GL_NO_ERROR);
- glUniformMatrix4fv(camera->gl_projection_matrix_loc, 1, GL_FALSE,
- &camera->projection_matrix.xx);
- assert(glGetError() == GL_NO_ERROR);
- glUniformMatrix4fv(camera->gl_view_matrix_loc, 1, GL_FALSE,
- &camera->view_matrix.xx);
- assert(glGetError() == GL_NO_ERROR);
- glUniformMatrix4fv(camera->gl_model_matrix_loc, 1, GL_FALSE,
- &camera->model_matrix.xx);
- assert(glGetError() == GL_NO_ERROR);
- glUniform1i(camera->gl_enable_tex2d_loc, 0);
- assert(glGetError() == GL_NO_ERROR);
- glUniform1i(camera->gl_tex2d_loc, 0);
- assert(glGetError() == GL_NO_ERROR);
- glUniform3fv(camera->gl_light_pos_loc, camera->light_count,
- &camera->light_pos_cam[0].x);
- assert(glGetError() == GL_NO_ERROR);
- glUniform3fv(camera->gl_light_color_loc, camera->light_count,
- &camera->light_color[0].r);
- assert(glGetError() == GL_NO_ERROR);
- gl_camera_material(camera, &material);
- assert(glGetError() == GL_NO_ERROR);
- glDisable(GL_CULL_FACE);
- assert(glGetError() == GL_NO_ERROR);
- glDepthRange(camera->clip_z_near, camera->clip_z_far);
- assert(glGetError() == GL_NO_ERROR);
-}
-
-void gl_camera_render_end (s_gl_camera *camera)
-{
- assert(camera);
- (void) camera;
- glUseProgram(0);
-}
-
-s_gl_camera * gl_camera_set_aspect_ratio (s_gl_camera *camera, uw w,
- uw h)
-{
- assert(camera);
- camera->aspect_ratio = (f64) (w ? w : 1) / (h ? h : 1);
- return camera;
-}
diff --git a/libkc3_window/sdl2/gl_camera.h b/libkc3_window/sdl2/gl_camera.h
deleted file mode 100644
index 20fbe53..0000000
--- a/libkc3_window/sdl2/gl_camera.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 GL_CAMERA_H
-#define GL_CAMERA_H
-
-#include "types.h"
-
-/* Stack-allocation compatible functions, call gl_camera_clean
- after use. */
-void gl_camera_clean (s_gl_camera *camera);
-s_gl_camera * gl_camera_init (s_gl_camera *camera, uw w, uw h);
-
-/* Heap-allocation functions, call gl_camera_delete after use. */
-void gl_camera_delete (s_gl_camera *camera);
-s_gl_camera * gl_camera_new (uw w, uw h);
-
-/* Operators. */
-void gl_camera_bind_texture (s_gl_camera *camera,
- GLuint texture);
-void gl_camera_material (s_gl_camera *camera,
- const s_gl_material *material);
-void gl_camera_render (s_gl_camera *camera);
-s_gl_camera * gl_camera_set_aspect_ratio (s_gl_camera *camera, uw w,
- uw h);
-
-#endif /* GL_CAMERA_H */
diff --git a/libkc3_window/sdl2/gl_cylinder.c b/libkc3_window/sdl2/gl_cylinder.c
deleted file mode 100644
index 62e2f92..0000000
--- a/libkc3_window/sdl2/gl_cylinder.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "gl_object.h"
-#include "gl_cylinder.h"
-
-void gl_cylinder_clean (s_gl_cylinder *cylinder)
-{
- assert(cylinder);
- gl_object_clean(&cylinder->object);
-}
-
-s_gl_cylinder * gl_cylinder_init (s_gl_cylinder *cylinder,
- uw segments_u, uw segments_v)
-{
- f64 angle;
- uw i;
- uw j;
- s_vec3 *p;
- f64 z;
- assert(cylinder);
- assert(segments_u);
- assert(segments_v);
- cylinder->segments_u = segments_u;
- cylinder->segments_v = segments_v;
- if (! gl_object_init(&cylinder->object) ||
- ! gl_object_allocate(&cylinder->object,
- segments_u * segments_v + 2,
- 6 * (segments_u + 1) * (segments_v + 2)))
- return NULL;
- p = cylinder->object.vertex.data;
- i = 0;
- while (i < segments_v) {
- z = (f64) i / segments_v;
- j = 0;
- while (j < segments_u) {
- angle = (f64) j / segments_u * M_PI * 2.0;
- p->x = cos(angle);
- p->y = sin(angle);
- p->z = z;
- p++;
- j++;
- }
- i++;
- }
- return cylinder;
-}
-
-void gl_cylinder_render (const s_gl_cylinder *cylinder)
-{
- assert(cylinder);
- (void) cylinder;
- glBegin(GL_POINTS);
- glEnd();
-}
diff --git a/libkc3_window/sdl2/gl_cylinder.h b/libkc3_window/sdl2/gl_cylinder.h
deleted file mode 100644
index b1e6edd..0000000
--- a/libkc3_window/sdl2/gl_cylinder.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 GL_CYLINDER_H
-#define GL_CYLINDER_H
-
-#include "types.h"
-
-s_gl_cylinder * gl_cylinder_init (s_gl_cylinder *cylinder,
- uw segments_u, uw segments_v);
-void gl_cylinder_render (const s_gl_cylinder *cylinder);
-
-#endif /* GL_CYLINDER_H */
diff --git a/libkc3_window/sdl2/gl_deprecated.c b/libkc3_window/sdl2/gl_deprecated.c
deleted file mode 100644
index 97cd0e7..0000000
--- a/libkc3_window/sdl2/gl_deprecated.c
+++ /dev/null
@@ -1,19 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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.
- */
-#define GL_SILENCE_DEPRECATION 1
-#include "gl_deprecated.h"
-
-const char * gl_error_string (GLenum error)
-{
- return (const char *) gluErrorString(error);
-}
diff --git a/libkc3_window/sdl2/gl_deprecated.h b/libkc3_window/sdl2/gl_deprecated.h
deleted file mode 100644
index f7fadbf..0000000
--- a/libkc3_window/sdl2/gl_deprecated.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 C3_GL_DEPRECATED_H
-#define C3_GL_DEPRECATED_H
-
-#include "types.h"
-
-const char * gl_error_string (GLenum error);
-
-#endif /* C3_GL_DEPRECATED_H */
diff --git a/libkc3_window/sdl2/gl_font.c b/libkc3_window/sdl2/gl_font.c
deleted file mode 100644
index 7a7065e..0000000
--- a/libkc3_window/sdl2/gl_font.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "gl_font.h"
-
-FT_Library g_ft = {0};
-
-void gl_font_clean (s_gl_font *font)
-{
- assert(font);
- FT_Done_Face(font->ft_face);
- str_clean(&font->path);
- str_clean(&font->real_path);
-}
-
-s_gl_font * gl_font_init (s_gl_font *font, const char *path,
- f32 point_per_pixel)
-{
- s_gl_font tmp = {0};
- assert(font);
- assert(path);
- str_init_copy_1(&tmp.path, path);
- if (! file_search(&tmp.path, sym_1("r"), &tmp.real_path)) {
- err_write_1("gl_font_init: file not found: ");
- err_puts(path);
- str_clean(&tmp.path);
- return NULL;
- }
- assert(glGetError() == GL_NO_ERROR);
- if (FT_New_Face(g_ft, tmp.real_path.ptr.pchar, 0, &tmp.ft_face)) {
- err_write_1("gl_font_init: error loading font: ");
- err_puts(tmp.real_path.ptr.pchar);
- str_clean(&tmp.path);
- str_clean(&tmp.real_path);
- return NULL;
- }
- tmp.point_per_pixel = point_per_pixel;
- *font = tmp;
- return font;
-}
-
-void gl_font_set_size (s_gl_font *font, f32 point_size)
-{
- f32 size;
- size = point_size / font->point_per_pixel;
- FT_Set_Pixel_Sizes(font->ft_face, 0, size);
-}
diff --git a/libkc3_window/sdl2/gl_font.h b/libkc3_window/sdl2/gl_font.h
deleted file mode 100644
index 738c0d5..0000000
--- a/libkc3_window/sdl2/gl_font.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 GL_FONT_H
-#define GL_FONT_H
-
-#include "types.h"
-
-extern FT_Library g_ft;
-
-/* Stack-allocation compatible functions, call gl_font_clean
- after use. */
-void gl_font_clean (s_gl_font *font);
-s_gl_font * gl_font_init (s_gl_font *font, const char *path,
- f32 point_per_pixel);
-
-/* Operators. */
-void gl_font_set_size (s_gl_font *font, f32 point_size);
-
-#endif /* GL_FONT_H */
diff --git a/libkc3_window/sdl2/gl_lines.c b/libkc3_window/sdl2/gl_lines.c
deleted file mode 100644
index 7ba19ef..0000000
--- a/libkc3_window/sdl2/gl_lines.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "gl_lines.h"
-#include "gl_vertex.h"
-
-s_gl_lines * gl_lines_allocate (s_gl_lines *lines, uw lines_count)
-{
- uw vertex_count;
- assert(lines);
- assert(lines_count);
- vertex_count = lines_count * 2;
- if (! array_init(&lines->vertex, sym_1("GL.Vertex[]"), 1,
- &vertex_count) ||
- ! array_allocate(&lines->vertex))
- return NULL;
- return lines;
-}
-
-void gl_lines_clean (s_gl_lines *lines)
-{
- assert(lines);
- array_clean(&lines->vertex);
- glDeleteVertexArrays(1, &lines->gl_vao);
- glDeleteBuffers(1, &lines->gl_vbo);
-}
-
-s_gl_lines * gl_lines_init (s_gl_lines *lines)
-{
- s_gl_lines tmp = {0};
- assert(glGetError() == GL_NO_ERROR);
- glGenVertexArrays(1, &tmp.gl_vao);
- glGenBuffers(1, &tmp.gl_vbo);
- assert(glGetError() == GL_NO_ERROR);
- *lines = tmp;
- return lines;
-}
-
-void gl_lines_render (const s_gl_lines *lines, uw lines_count)
-{
- assert(lines);
- if (lines_count > lines->vertex.count / 2)
- lines_count = lines->vertex.count / 2;
- assert(glGetError() == GL_NO_ERROR);
- glBindVertexArray(lines->gl_vao);
- assert(glGetError() == GL_NO_ERROR);
- glBindVertexArray(lines->gl_vao);
- assert(glGetError() == GL_NO_ERROR);
- glDrawArrays(GL_LINES, 0, lines_count * 2);
- assert(glGetError() == GL_NO_ERROR);
-}
-
-bool gl_lines_update (s_gl_lines *lines, uw lines_count)
-{
- //GLenum gl_error;
- assert(lines);
- assert(lines->gl_vao);
- assert(lines->gl_vbo);
- assert(lines->vertex.data);
- assert(glGetError() == GL_NO_ERROR);
- if (lines_count > lines->vertex.count / 2)
- lines_count = lines->vertex.count / 2;
- glBindVertexArray(lines->gl_vao);
- assert(glGetError() == GL_NO_ERROR);
- glBindBuffer(GL_ARRAY_BUFFER, lines->gl_vbo);
- assert(glGetError() == GL_NO_ERROR);
- glBufferData(GL_ARRAY_BUFFER, lines_count * 2 * sizeof(s_gl_vertex),
- lines->vertex.data, GL_DYNAMIC_DRAW);
- assert(glGetError() == GL_NO_ERROR);
- gl_vertex_attrib();
- assert(glGetError() == GL_NO_ERROR);
- return true;
-}
diff --git a/libkc3_window/sdl2/gl_lines.h b/libkc3_window/sdl2/gl_lines.h
deleted file mode 100644
index d6f2a97..0000000
--- a/libkc3_window/sdl2/gl_lines.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 GL_LINES_H
-#define GL_LINES_H
-
-#include "types.h"
-
-/* Stack-allocation compatible functions, call gl_lines_clean
- after use. */
-void gl_lines_clean (s_gl_lines *lines);
-s_gl_lines * gl_lines_init (s_gl_lines *lines);
-
-/* Heap-allocation functions, call gl_lines_delete after use. */
-void gl_lines_delete (s_gl_lines *lines);
-s_gl_lines * gl_lines_new (void);
-
-/* Operators. */
-s_gl_lines * gl_lines_allocate (s_gl_lines *lines, uw lines_count);
-bool gl_lines_update (s_gl_lines *lines, uw lines_count);
-
-/* Observers. */
-void gl_lines_render (const s_gl_lines *lines, uw lines_count);
-void gl_lines_render_wireframe (const s_gl_lines *lines,
- uw lines_count);
-
-#endif /* GL_LINES_H */
diff --git a/libkc3_window/sdl2/gl_object.c b/libkc3_window/sdl2/gl_object.c
deleted file mode 100644
index b99adb5..0000000
--- a/libkc3_window/sdl2/gl_object.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "gl_deprecated.h"
-#include "gl_object.h"
-#include "gl_vertex.h"
-
-s_gl_object * gl_object_allocate (s_gl_object *object, uw vertex_count,
- uw triangle_count)
-{
- assert(object);
- assert(vertex_count);
- assert(triangle_count);
- if (! array_init(&object->vertex, sym_1("GL.Vertex[]"), 1,
- &vertex_count) ||
- ! array_allocate(&object->vertex) ||
- ! array_init(&object->triangle, sym_1("GL.Triangle[]"), 1,
- &triangle_count) ||
- ! array_allocate(&object->triangle))
- return NULL;
- return object;
-}
-
-void gl_object_clean (s_gl_object *object)
-{
- assert(object);
- assert(glGetError() == GL_NO_ERROR);
- if (object->gl_vao)
- glDeleteVertexArrays(1, &object->gl_vao);
- assert(glGetError() == GL_NO_ERROR);
- if (object->gl_vbo)
- glDeleteBuffers(1, &object->gl_vbo);
- assert(glGetError() == GL_NO_ERROR);
- if (object->gl_ebo)
- glDeleteBuffers(1, &object->gl_ebo);
- assert(glGetError() == GL_NO_ERROR);
- array_clean(&object->vertex);
- array_clean(&object->triangle);
-}
-
-s_gl_object * gl_object_init (s_gl_object *object)
-{
- s_gl_object tmp = {0};
- assert(glGetError() == GL_NO_ERROR);
- glGenVertexArrays(1, &tmp.gl_vao);
- assert(glGetError() == GL_NO_ERROR);
- glGenBuffers(1, &tmp.gl_vbo);
- assert(glGetError() == GL_NO_ERROR);
- glGenBuffers(1, &tmp.gl_ebo);
- assert(glGetError() == GL_NO_ERROR);
- *object = tmp;
- return object;
-}
-
-void gl_object_render (const s_gl_object *object)
-{
- GLenum error;
- assert(object);
- assert(glGetError() == GL_NO_ERROR);
- glBindVertexArray(object->gl_vao);
- assert(glGetError() == GL_NO_ERROR);
- glBindBuffer(GL_ARRAY_BUFFER, object->gl_vbo);
- assert(glGetError() == GL_NO_ERROR);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object->gl_ebo);
- assert(glGetError() == GL_NO_ERROR);
- glDrawElements(GL_TRIANGLES, object->triangle.count * 3, GL_UNSIGNED_INT,
- NULL);
- if ((error = glGetError()) != GL_NO_ERROR) {
- err_write_1("gl_object_render: glDrawElements: ");
- err_puts(gl_error_string(error));
- assert(! "gl_object_render: glDrawElements");
- }
- assert(glGetError() == GL_NO_ERROR);
-}
-
-void gl_object_render_wireframe (const s_gl_object *object)
-{
- assert(object);
- assert(glGetError() == GL_NO_ERROR);
- glBindVertexArray(object->gl_vao);
- assert(glGetError() == GL_NO_ERROR);
- glBindBuffer(GL_ARRAY_BUFFER, object->gl_vbo);
- assert(glGetError() == GL_NO_ERROR);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object->gl_ebo);
- assert(glGetError() == GL_NO_ERROR);
- glDrawElements(GL_LINE_LOOP, object->triangle.count * 3,
- GL_UNSIGNED_INT,
- NULL);
- assert(glGetError() == GL_NO_ERROR);
-}
-
-void gl_object_transform (s_gl_object *object, const s_mat4 *matrix)
-{
- uw i;
- s_gl_vertex *vertex;
- assert(object);
- assert(matrix);
- vertex = object->vertex.data;
- i = 0;
- while (i < object->vertex.count) {
- gl_vertex_transform(vertex, matrix);
- vertex++;
- i++;
- }
-}
-
-bool gl_object_update (s_gl_object *object)
-{
- //GLenum gl_error;
- assert(object);
- assert(object->gl_vao);
- assert(object->gl_vbo);
- assert(object->gl_ebo);
- assert(object->vertex.data);
- assert(object->triangle.data);
- assert(glGetError() == GL_NO_ERROR);
- glBindVertexArray(object->gl_vao);
- assert(glGetError() == GL_NO_ERROR);
- glBindBuffer(GL_ARRAY_BUFFER, object->gl_vbo);
- assert(glGetError() == GL_NO_ERROR);
- glBufferData(GL_ARRAY_BUFFER, object->vertex.count * sizeof(s_gl_vertex),
- object->vertex.data, GL_DYNAMIC_DRAW);
- assert(glGetError() == GL_NO_ERROR);
- gl_vertex_attrib();
- assert(glGetError() == GL_NO_ERROR);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object->gl_ebo);
- assert(glGetError() == GL_NO_ERROR);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, object->triangle.count * sizeof(s_gl_triangle),
- object->triangle.data, GL_DYNAMIC_DRAW);
- assert(glGetError() == GL_NO_ERROR);
- return true;
-}
diff --git a/libkc3_window/sdl2/gl_object.h b/libkc3_window/sdl2/gl_object.h
deleted file mode 100644
index cea10d3..0000000
--- a/libkc3_window/sdl2/gl_object.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 GL_OBJECT_H
-#define GL_OBJECT_H
-
-#include "types.h"
-
-/* Stack-allocation compatible functions, call gl_object_clean
- after use. */
-void gl_object_clean (s_gl_object *object);
-s_gl_object * gl_object_init (s_gl_object *object);
-
-/* Heap-allocation functions, call gl_object_delete after use. */
-void gl_object_delete (s_gl_object *object);
-s_gl_object * gl_object_new (void);
-
-/* Operators. */
-s_gl_object * gl_object_allocate (s_gl_object *object, uw vertex_count,
- uw index_count);
-void gl_object_transform (s_gl_object *object,
- const s_mat4 *matrix);
-bool gl_object_update (s_gl_object *object);
-
-/* Observers. */
-void gl_object_render (const s_gl_object *object);
-void gl_object_render_wireframe (const s_gl_object *object);
-
-#endif /* GL_OBJECT_H */
diff --git a/libkc3_window/sdl2/gl_ortho.c b/libkc3_window/sdl2/gl_ortho.c
deleted file mode 100644
index 54d7f10..0000000
--- a/libkc3_window/sdl2/gl_ortho.c
+++ /dev/null
@@ -1,352 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "gl_deprecated.h"
-#include "mat4.h"
-#include "gl_ortho.h"
-#include "gl_square.h"
-
-static const char * g_gl_ortho_vertex_shader_src =
- "#version 330 core\n"
- "layout (location = 0) in vec3 iPos;\n"
- "layout (location = 1) in vec3 iNormal;\n"
- "layout (location = 2) in vec2 iTexCoord;\n"
- "out vec3 ioFragNormal;\n"
- "out vec2 ioTexCoord;\n"
- "uniform mat4 uProjectionMatrix;\n"
- "uniform mat4 uViewMatrix;\n"
- "uniform mat4 uModelMatrix;\n"
- "void main() {\n"
- " gl_Position = vec4(uProjectionMatrix * uViewMatrix * \n"
- " uModelMatrix * vec4(iPos, 1.0));\n"
- " ioTexCoord = iTexCoord;\n"
- " ioFragNormal = vec3(mat3(transpose(inverse(uModelMatrix))) *\n"
- " iNormal);\n"
- "}\n";
-
-static const char * g_gl_ortho_fragment_shader_src =
- "#version 330 core\n"
- "in vec3 ioFragNormal;\n"
- "in vec2 ioTexCoord;\n"
- "out vec4 oFragColor;\n"
- "uniform vec4 uColor;\n"
- "uniform bool uEnableTex2D;\n"
- "uniform sampler2D uTex2D;\n"
- "void main() {\n"
- " vec4 texColor = texture(uTex2D, ioTexCoord);\n"
- " if (uEnableTex2D) {\n"
- " oFragColor = vec4(texColor[0] * uColor[0],\n"
- " texColor[1] * uColor[1],\n"
- " texColor[2] * uColor[2],\n"
- " texColor[3] * uColor[3]);\n"
- " }\n"
- " else\n"
- " oFragColor = uColor;\n"
- "}\n";
-
-void gl_ortho_bind_texture (s_gl_ortho *ortho, GLuint texture)
-{
- assert(ortho);
- assert(glGetError() == GL_NO_ERROR);
- if (! texture) {
- glActiveTexture(GL_TEXTURE0);
- assert(glGetError() == GL_NO_ERROR);
- glBindTexture(GL_TEXTURE_2D, 0);
- assert(glGetError() == GL_NO_ERROR);
- glUniform1i(ortho->gl_enable_tex2d_loc, 0);
- assert(glGetError() == GL_NO_ERROR);
- glUniform1i(ortho->gl_tex2d_loc, 0);
- assert(glGetError() == GL_NO_ERROR);
- return;
- }
- glActiveTexture(GL_TEXTURE0);
- assert(glGetError() == GL_NO_ERROR);
- glBindTexture(GL_TEXTURE_2D, texture);
- assert(glGetError() == GL_NO_ERROR);
- glUniform1i(ortho->gl_enable_tex2d_loc, 1);
- assert(glGetError() == GL_NO_ERROR);
- glUniform1i(ortho->gl_tex2d_loc, 0);
- assert(glGetError() == GL_NO_ERROR);
-}
-
-void gl_ortho_clean (s_gl_ortho *ortho)
-{
- assert(ortho);
- assert(glGetError() == GL_NO_ERROR);
- glDeleteProgram(ortho->gl_shader_program);
- assert(glGetError() == GL_NO_ERROR);
- gl_square_clean(&ortho->square);
- assert(glGetError() == GL_NO_ERROR);
-}
-
-void gl_ortho_color (s_gl_ortho *ortho, f32 r, f32 g, f32 b, f32 a)
-{
- s_rgba color = {r, g, b, a};
- assert(ortho);
- assert(glGetError() == GL_NO_ERROR);
- glUniform4fv(ortho->gl_color_loc, 1, &color.r);
- assert(glGetError() == GL_NO_ERROR);
-}
-
-void gl_ortho_delete (s_gl_ortho *ortho)
-{
- gl_ortho_clean(ortho);
- free(ortho);
-}
-
-s_gl_ortho * gl_ortho_init (s_gl_ortho *ortho)
-{
- GLuint fragment_shader;
- GLint success;
- GLuint vertex_shader;
- assert(ortho);
- if (! gl_square_init(&ortho->square, 2, 2))
- return NULL;
- mat4_init_identity(&ortho->projection_matrix);
- mat4_ortho(&ortho->projection_matrix, -1, 1, -1, 1, 0, 1);
- ortho->position.x = 0.0f;
- ortho->position.y = 0.0f;
- ortho->position.z = 0.0f;
- ortho->rotation.x = 0.0f;
- ortho->rotation.y = 0.0f;
- ortho->rotation.z = 0.0f;
- ortho->scale.x = 1.0f;
- ortho->scale.y = 1.0f;
- ortho->scale.z = 1.0f;
- mat4_init_identity(&ortho->view_matrix);
- mat4_init_identity(&ortho->model_matrix);
- vertex_shader = glCreateShader(GL_VERTEX_SHADER);
- glShaderSource(vertex_shader, 1, &g_gl_ortho_vertex_shader_src,
- NULL);
- glCompileShader(vertex_shader);
- glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
- if (! success) {
- char info_log[512];
- glGetShaderInfoLog(vertex_shader, sizeof(info_log), NULL, info_log);
- err_write_1("gl_ortho_init: shader compilation failed: ");
- err_puts(info_log);
- }
- fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
- glShaderSource(fragment_shader, 1, &g_gl_ortho_fragment_shader_src,
- NULL);
- glCompileShader(fragment_shader);
- glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
- if (! success) {
- char info_log[512];
- glGetShaderInfoLog(fragment_shader, sizeof(info_log), NULL, info_log);
- err_write_1("gl_ortho_init: shader compilation failed: ");
- err_puts(info_log);
- }
- ortho->gl_shader_program = glCreateProgram();
- assert(glGetError() == GL_NO_ERROR);
- glAttachShader(ortho->gl_shader_program, vertex_shader);
- assert(glGetError() == GL_NO_ERROR);
- glAttachShader(ortho->gl_shader_program, fragment_shader);
- assert(glGetError() == GL_NO_ERROR);
- glLinkProgram(ortho->gl_shader_program);
- assert(glGetError() == GL_NO_ERROR);
- glDeleteShader(vertex_shader);
- assert(glGetError() == GL_NO_ERROR);
- glDeleteShader(fragment_shader);
- assert(glGetError() == GL_NO_ERROR);
- ortho->gl_projection_matrix_loc =
- glGetUniformLocation(ortho->gl_shader_program, "uProjectionMatrix");
- assert(glGetError() == GL_NO_ERROR);
- ortho->gl_view_matrix_loc =
- glGetUniformLocation(ortho->gl_shader_program, "uViewMatrix");
- assert(glGetError() == GL_NO_ERROR);
- ortho->gl_model_matrix_loc =
- glGetUniformLocation(ortho->gl_shader_program, "uModelMatrix");
- assert(glGetError() == GL_NO_ERROR);
- ortho->gl_enable_tex2d_loc =
- glGetUniformLocation(ortho->gl_shader_program, "uEnableTex2D");
- assert(glGetError() == GL_NO_ERROR);
- ortho->gl_tex2d_loc =
- glGetUniformLocation(ortho->gl_shader_program, "uTex2D");
- assert(glGetError() == GL_NO_ERROR);
- ortho->gl_color_loc =
- glGetUniformLocation(ortho->gl_shader_program, "uColor");
- assert(glGetError() == GL_NO_ERROR);
- return ortho;
-}
-
-s_gl_ortho * gl_ortho_new (void)
-{
- s_gl_ortho *ortho;
- ortho = calloc(1, sizeof(s_gl_ortho));
- if (! ortho) {
- err_puts("gl_ortho_new: failed to allocate memory");
- return NULL;
- }
- if (! gl_ortho_init(ortho)) {
- free(ortho);
- return NULL;
- }
- return ortho;
-}
-
-void gl_ortho_rect (s_gl_ortho *ortho, f32 x, f32 y, f32 w, f32 h)
-{
- s_mat4 matrix;
- assert(ortho);
- assert(glGetError() == GL_NO_ERROR);
- matrix = ortho->model_matrix;
- mat4_translate(&ortho->model_matrix, x, y, 0.0f);
- mat4_scale(&ortho->model_matrix, w, h, 1.0f);
- gl_ortho_update_model_matrix(ortho);
- assert(glGetError() == GL_NO_ERROR);
- gl_square_render(&ortho->square);
- assert(glGetError() == GL_NO_ERROR);
- ortho->model_matrix = matrix;
- gl_ortho_update_model_matrix(ortho);
-}
-
-void gl_ortho_render (s_gl_ortho *ortho)
-{
- GLenum error;
- assert(ortho);
- assert(glGetError() == GL_NO_ERROR);
- glUseProgram(ortho->gl_shader_program);
- assert(glGetError() == GL_NO_ERROR);
- glUniformMatrix4fv(ortho->gl_projection_matrix_loc, 1, GL_FALSE,
- &ortho->projection_matrix.xx);
- if ((error = glGetError()) != GL_NO_ERROR) {
- err_write_1("gl_ortho_render: glUniformMatrix4fv: ");
- err_puts(gl_error_string(error));
- assert(! "gl_ortho_render: glUniformMatrix4fv");
- }
- assert(glGetError() == GL_NO_ERROR);
- glUniformMatrix4fv(ortho->gl_view_matrix_loc, 1, GL_FALSE,
- &ortho->view_matrix.xx);
- assert(glGetError() == GL_NO_ERROR);
- glUniformMatrix4fv(ortho->gl_model_matrix_loc, 1, GL_FALSE,
- &ortho->model_matrix.xx);
- assert(glGetError() == GL_NO_ERROR);
- glUniform1i(ortho->gl_enable_tex2d_loc, 0);
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, 0);
- assert(glGetError() == GL_NO_ERROR);
- glUniform1i(ortho->gl_tex2d_loc, 0);
- assert(glGetError() == GL_NO_ERROR);
- glUniform4f(ortho->gl_color_loc, 1.0f, 1.0f, 1.0f, 1.0f);
- assert(glGetError() == GL_NO_ERROR);
- glDepthRange(ortho->clip_z_near, ortho->clip_z_far);
- assert(glGetError() == GL_NO_ERROR);
-}
-
-void gl_ortho_render_end (s_gl_ortho *ortho)
-{
- assert(ortho);
- (void) ortho;
- assert(glGetError() == GL_NO_ERROR);
- glUseProgram(0);
- assert(glGetError() == GL_NO_ERROR);
-}
-
-void gl_ortho_resize (s_gl_ortho *ortho, f32 x1, f32 x2, f32 y1, f32 y2,
- f32 clip_z_near, f32 clip_z_far)
-{
- assert(ortho);
- mat4_init_identity(&ortho->projection_matrix);
- mat4_ortho(&ortho->projection_matrix, x1, x2, y1, y2,
- clip_z_near, clip_z_far);
-}
-
-void gl_ortho_text_render (s_gl_ortho *ortho, const s_gl_text *text)
-{
- assert(ortho);
- assert(text);
- gl_ortho_bind_texture(ortho, text->texture);
- gl_ortho_rect(ortho, 0, 0, text->pt_w, text->pt_h);
- gl_ortho_bind_texture(ortho, 0);
-}
-
-void gl_ortho_text_render_outline (s_gl_ortho *ortho, s_gl_text *text,
- f64 x, f64 y)
-{
- s_mat4 matrix;
- assert(glGetError() == GL_NO_ERROR);
- glEnable(GL_BLEND);
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
- GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- assert(glGetError() == GL_NO_ERROR);
- gl_ortho_bind_texture(ortho, text->texture);
- assert(glGetError() == GL_NO_ERROR);
- gl_ortho_color(ortho, 1.0f, 1.0f, 1.0f, 1.0f);
- assert(glGetError() == GL_NO_ERROR);
- matrix = ortho->model_matrix;
- gl_ortho_rect(ortho, x - 1.0, y - 1.0, text->pt_w, text->pt_h);
- gl_ortho_rect(ortho, x, y - 1.0, text->pt_w, text->pt_h);
- gl_ortho_rect(ortho, x + 1.0, y - 1.0, text->pt_w, text->pt_h);
- gl_ortho_rect(ortho, x - 1.0, y, text->pt_w, text->pt_h);
- //gl_ortho_rect(ortho, x, y, text->pt_w, text->pt_h);
- gl_ortho_rect(ortho, x + 1.0, y, text->pt_w, text->pt_h);
- gl_ortho_rect(ortho, x - 1.0, y + 1.0, text->pt_w, text->pt_h);
- gl_ortho_rect(ortho, x, y + 1.0, text->pt_w, text->pt_h);
- gl_ortho_rect(ortho, x + 1.0, y + 1.0, text->pt_w, text->pt_h);
- gl_ortho_color(ortho, 0.0f, 0.0f, 0.0f, 1.0f);
- assert(glGetError() == GL_NO_ERROR);
- gl_ortho_rect(ortho, x, y, text->pt_w, text->pt_h);
- assert(glGetError() == GL_NO_ERROR);
- ortho->model_matrix = matrix;
- gl_ortho_update_model_matrix(ortho);
- assert(glGetError() == GL_NO_ERROR);
-}
-
-void gl_ortho_update_model_matrix (s_gl_ortho *ortho)
-{
- assert(ortho);
- assert(glGetError() == GL_NO_ERROR);
- glUniformMatrix4fv(ortho->gl_model_matrix_loc, 1, GL_FALSE,
- &ortho->model_matrix.xx);
- assert(glGetError() == GL_NO_ERROR);
- /*
- err_puts("gl_ortho_update_model_matrix projection matrix");
- mat4_buf_inspect(&g_c3_env.err, &ortho->projection_matrix);
- err_puts("view matrix");
- mat4_buf_inspect(&g_c3_env.err, &ortho->view_matrix);
- err_puts("model matrix");
- mat4_buf_inspect(&g_c3_env.err, &ortho->model_matrix);
- buf_flush(&g_c3_env.err);
- */
-}
-
-void gl_ortho_update_view_matrix (s_gl_ortho *ortho)
-{
- assert(ortho);
- assert(glGetError() == GL_NO_ERROR);
- mat4_init_identity(&ortho->view_matrix);
- mat4_translate(&ortho->view_matrix, ortho->position.x,
- ortho->position.y, ortho->position.z);
- mat4_rotate_axis(&ortho->view_matrix, ortho->rotation.x,
- &(s_vec3) { 1.0f, 0.0f, 0.0f });
- mat4_rotate_axis(&ortho->view_matrix, ortho->rotation.y,
- &(s_vec3) { 0.0f, 1.0f, 0.0f });
- mat4_rotate_axis(&ortho->view_matrix, ortho->rotation.z,
- &(s_vec3) { 0.0f, 0.0f, 1.0f });
- mat4_scale(&ortho->view_matrix, ortho->scale.x,
- ortho->scale.y, ortho->scale.z);
- glUniformMatrix4fv(ortho->gl_view_matrix_loc, 1, GL_FALSE,
- &ortho->view_matrix.xx);
- assert(glGetError() == GL_NO_ERROR);
-}
-
-void gl_ortho_vtext_render (s_gl_ortho *ortho, const s_gl_text *text)
-{
- assert(ortho);
- assert(text);
- gl_ortho_bind_texture(ortho, text->texture);
- gl_ortho_rect(ortho, 0, -text->pt_h, text->pt_w, text->pt_h);
- gl_ortho_bind_texture(ortho, 0);
-}
diff --git a/libkc3_window/sdl2/gl_ortho.h b/libkc3_window/sdl2/gl_ortho.h
deleted file mode 100644
index 0254055..0000000
--- a/libkc3_window/sdl2/gl_ortho.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 GL_ORTHO_H
-#define GL_ORTHO_H
-
-#include "types.h"
-
-/* Stack-allocation compatible functions, call gl_ortho_clean
- after use. */
-void gl_ortho_clean (s_gl_ortho *ortho);
-s_gl_ortho * gl_ortho_init (s_gl_ortho *ortho);
-
-/* Heap-allocation functions, call gl_ortho_delete after use. */
-void gl_ortho_delete (s_gl_ortho *ortho);
-s_gl_ortho * gl_ortho_new (void);
-
-/* Operators. */
-void gl_ortho_bind_texture (s_gl_ortho *ortho, GLuint texture);
-void gl_ortho_color (s_gl_ortho *ortho, f32 r, f32 g, f32 b,
- f32 a);
-void gl_ortho_rect (s_gl_ortho *ortho, f32 x1, f32 x2, f32 y1,
- f32 y2);
-void gl_ortho_render (s_gl_ortho *ortho);
-void gl_ortho_render_end (s_gl_ortho *ortho);
-void gl_ortho_resize (s_gl_ortho *ortho, f32 x1, f32 x2, f32 y1,
- f32 y2, f32 clip_z_near, f32 clip_z_far);
-void gl_ortho_text_render (s_gl_ortho *ortho,
- const s_gl_text *text);
-void gl_ortho_text_render_outline (s_gl_ortho *ortho,
- s_gl_text *text,
- f64 x, f64 y);
-void gl_ortho_update_model_matrix (s_gl_ortho *ortho);
-void gl_ortho_update_view_matrix (s_gl_ortho *ortho);
-void gl_ortho_vtext_render (s_gl_ortho *ortho,
- const s_gl_text *text);
-
-#endif /* GL_ORTHO_H */
diff --git a/libkc3_window/sdl2/gl_sphere.c b/libkc3_window/sdl2/gl_sphere.c
deleted file mode 100644
index a05e044..0000000
--- a/libkc3_window/sdl2/gl_sphere.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "gl_object.h"
-#include "gl_sphere.h"
-
-void gl_sphere_clean (s_gl_sphere *sphere)
-{
- assert(sphere);
- gl_object_clean(&sphere->object);
-}
-
-void gl_sphere_delete (s_gl_sphere *sphere)
-{
- assert(sphere);
- gl_sphere_clean(sphere);
- free(sphere);
-}
-
-s_gl_sphere * gl_sphere_init (s_gl_sphere *sphere, uw seg_u, uw seg_v)
-{
- f64 angle_i;
- f64 angle_j;
- uw i;
- uw j;
- s_gl_vertex *vertex;
- f64 r;
- s_gl_sphere tmp = {0};
- s_gl_triangle *triangle;
- f64 z;
- assert(sphere);
- if (seg_u < 3)
- seg_u = 3;
- if (seg_v < 1)
- seg_v = 1;
- tmp.segments_u = seg_u;
- tmp.segments_v = seg_v;
- if (! gl_object_init(&tmp.object) ||
- ! gl_object_allocate(&tmp.object, (seg_u + 1) * (seg_v + 2),
- 2 * seg_u * (seg_v + 1)))
- return NULL;
- vertex = tmp.object.vertex.data;
- i = 0;
- while (i <= seg_v + 1) {
- angle_i = (f64) i * M_PI / (seg_v + 1);
- r = sin(angle_i);
- z = cos(angle_i);
- j = 0;
- while (j <= seg_u) {
- angle_j = j * M_PI * 2.0 / seg_u;
- vertex->pos_x = cos(angle_j) * r;
- vertex->pos_y = sin(angle_j) * r;
- vertex->pos_z = z;
- vertex->normal_x = vertex->pos_x;
- vertex->normal_y = vertex->pos_y;
- vertex->normal_z = vertex->pos_z;
- vertex->tex_coord_x = (f64) (seg_u - j) / seg_u;
- vertex->tex_coord_y = (f64) i / (seg_v + 1);
- vertex++;
- j++;
- }
- i++;
- }
- triangle = tmp.object.triangle.data;
- i = 0;
- while (i < seg_v + 1) {
- j = 0;
- while (j < seg_u) {
- triangle->a = i * (seg_u + 1) + j;
- triangle->b = (i + 1) * (seg_u + 1) + j;
- triangle->c = (i + 1) * (seg_u + 1) + j + 1;
- triangle++;
- triangle->a = i * (seg_u + 1) + j;
- triangle->b = (i + 1) * (seg_u + 1) + j + 1;
- triangle->c = i * (seg_u + 1) + j + 1;
- triangle++;
- j++;
- }
- i++;
- }
- *sphere = tmp;
- return sphere;
-}
-
-s_gl_sphere * gl_sphere_new (uw segments_u, uw segments_v)
-{
- s_gl_sphere *sphere;
- sphere = calloc(1, sizeof(s_gl_sphere));
- if (! sphere) {
- err_puts("gl_sphere_new: failed to allocate memory");
- return NULL;
- }
- if (! gl_sphere_init(sphere, segments_u, segments_v)) {
- free(sphere);
- return NULL;
- }
- return sphere;
-}
-
-void gl_sphere_render (const s_gl_sphere *sphere)
-{
- assert(sphere);
- gl_object_render(&sphere->object);
-}
-
-/*
-void gl_sphere_render_wireframe (const s_gl_sphere *sphere)
-{
- uw i;
- uw j;
- s_gl_3d *p[3];
- uw seg_u;
- uw seg_v;
- assert(sphere);
- seg_u = sphere->segments_u;
- seg_v = sphere->segments_v;
- // first row
- j = 0;
- while (j < seg_u + 1) {
- glBegin(GL_LINE_STRIP);
- p[0] = sphere->vertex + seg_u * seg_v;
- p[1] = sphere->vertex + j % seg_u;
- p[2] = sphere->vertex + (j + 1) % seg_u;
- gl_vertex_3d(p[0]);
- gl_vertex_3d(p[1]);
- gl_vertex_3d(p[2]);
- glEnd();
- j++;
- }
- // whole
- i = 1;
- while (i < seg_v) {
- j = 0;
- while (j < seg_u + 1) {
- glBegin(GL_LINE_STRIP);
- p[0] = sphere->vertex + (i - 1) * seg_u + j % seg_u;
- p[1] = sphere->vertex + i * seg_u + j % seg_u;
- p[2] = sphere->vertex + i * seg_u + (j + 1) % seg_u;
- gl_vertex_3d(p[0]);
- gl_vertex_3d(p[1]);
- gl_vertex_3d(p[2]);
- glEnd();
- j++;
- }
- i++;
- }
- glBegin(GL_LINES);
- j = 0;
- while (j < seg_u + 1) {
- p[0] = sphere->vertex + seg_u * seg_v + 1;
- p[1] = sphere->vertex + (seg_v - 1) * seg_u + j % seg_u;
- gl_vertex_3d(p[0]);
- gl_vertex_3d(p[1]);
- j++;
- }
- glEnd();
-}
-*/
diff --git a/libkc3_window/sdl2/gl_sphere.h b/libkc3_window/sdl2/gl_sphere.h
deleted file mode 100644
index 81e6611..0000000
--- a/libkc3_window/sdl2/gl_sphere.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 GL_SPHERE_H
-#define GL_SPHERE_H
-
-#include "types.h"
-
-/* Stack-allocation compatible functions, call gl_sphere_clean after
- use. */
-void gl_sphere_clean (s_gl_sphere *sphere);
-s_gl_sphere * gl_sphere_init (s_gl_sphere *sphere, uw segments_u,
- uw segments_v);
-
-/* Heap-allocation functions, call gl_sphere_delete after use. */
-void gl_sphere_delete (s_gl_sphere *sphere);
-s_gl_sphere * gl_sphere_new (uw segments_u, uw segments_v);
-
-/* Observers. */
-void gl_sphere_render (const s_gl_sphere *sphere);
-void gl_sphere_render_wireframe (const s_gl_sphere *sphere);
-
-#endif /* GL_SPHERE_H */
diff --git a/libkc3_window/sdl2/gl_sprite.c b/libkc3_window/sdl2/gl_sprite.c
deleted file mode 100644
index dc618d4..0000000
--- a/libkc3_window/sdl2/gl_sprite.c
+++ /dev/null
@@ -1,341 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "gl_deprecated.h"
-#include "gl_object.h"
-#include "gl_sprite.h"
-#include "gl_triangle.h"
-
-void gl_sprite_clean (s_gl_sprite *sprite)
-{
- assert(sprite);
- str_clean(&sprite->path);
- str_clean(&sprite->real_path);
- glDeleteTextures(sprite->frame_count, sprite->texture);
- free(sprite->texture);
-}
-
-static bool png_info_to_gl_info (s32 png_color_type,
- s32 png_bit_depth,
- GLenum *gl_format,
- GLint *gl_internal_format,
- GLenum *gl_type,
- u8 *components)
-{
- switch (png_bit_depth) {
- case 8: *gl_type = GL_UNSIGNED_BYTE; break;
- case 16: *gl_type = GL_UNSIGNED_SHORT; break;
- default: *gl_type = 0; return false;
- }
- switch (png_color_type) {
- case PNG_COLOR_TYPE_GRAY:
- *components = 1;
- *gl_format = GL_RED;
- switch (png_bit_depth) {
- case 8: *gl_internal_format = GL_RED; break;
- case 16: *gl_internal_format = GL_RED; break;
- default: *gl_internal_format = 0; return false;
- }
- break;
- case PNG_COLOR_TYPE_GRAY_ALPHA:
- *components = 2;
- *gl_format = GL_RG;
- switch (png_bit_depth) {
- case 8: *gl_internal_format = GL_RG; break;
- case 16: *gl_internal_format = GL_RG; break;
- default: *gl_internal_format = 0; return false;
- }
- break;
- case PNG_COLOR_TYPE_RGB:
- *components = 3;
- *gl_format = GL_RGB;
- switch (png_bit_depth) {
- case 8: *gl_internal_format = GL_RGB; break;
- case 16: *gl_internal_format = GL_RGB; break;
- default: *gl_internal_format = 0; return false;
- }
- break;
- case PNG_COLOR_TYPE_RGBA:
- *components = 4;
- *gl_format = GL_RGBA;
- switch (png_bit_depth) {
- case 8: *gl_internal_format = GL_RGBA; break;
- case 16: *gl_internal_format = GL_RGBA; break;
- default: *gl_internal_format = 0; return false;
- }
- break;
- default:
- *components = 0;
- *gl_format = 0;
- *gl_internal_format = 0;
- return false;
- }
- return true;
-}
-
-s_gl_sprite * gl_sprite_init (s_gl_sprite *sprite, const char *path,
- uw dim_x, uw dim_y, uw frame_count,
- f32 point_per_pixel)
-{
- u8 *data;
- FILE *fp;
- GLenum gl_format;
- GLint gl_internal_format;
- GLenum gl_type;
- uw i;
- s32 png_bit_depth;
- s32 png_color_type;
- u8 png_components;
- png_bytep png_data;
- u32 png_h;
- u8 png_header[8]; // maximum size is 8
- png_infop png_info;
- uw png_pixel_size;
- png_structp png_read;
- png_bytep *png_row;
- u32 png_w;
- u8 *sprite_data;
- uw sprite_stride;
- uw x;
- uw y;
- uw v;
- s_gl_sprite tmp = {0};
- assert(sprite);
- assert(path);
- assert(dim_x);
- assert(dim_y);
- assert(glGetError() == GL_NO_ERROR);
- tmp.frame_count = (frame_count > 0) ? frame_count :
- (dim_x * dim_y);
- str_init_copy_1(&tmp.path, path);
- if (! file_search(&tmp.path, sym_1("r"), &tmp.real_path)) {
- err_write_1("gl_sprite_init: file not found: ");
- err_puts(path);
- str_clean(&tmp.path);
- return NULL;
- }
- fp = fopen(tmp.real_path.ptr.pchar, "rb");
- if (! fp) {
- err_write_1("gl_sprite_init: fopen: ");
- err_puts(tmp.real_path.ptr.pchar);
- str_clean(&tmp.path);
- str_clean(&tmp.real_path);
- return NULL;
- }
- if (fread(png_header, 1, sizeof(png_header), fp) !=
- sizeof(png_header)) {
- err_write_1("gl_sprite_init: fread: ");
- err_puts(tmp.real_path.ptr.pchar);
- fclose(fp);
- str_clean(&tmp.path);
- str_clean(&tmp.real_path);
- return NULL;
- }
- if (png_sig_cmp(png_header, 0, sizeof(png_header))) {
- err_write_1("gl_sprite_init: not a png: ");
- err_puts(tmp.real_path.ptr.pchar);
- fclose(fp);
- str_clean(&tmp.path);
- str_clean(&tmp.real_path);
- return NULL;
- }
- png_read = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL,
- NULL);
- if (! png_read) {
- err_write_1("gl_sprite_init: png_create_read_struct: ");
- err_puts(tmp.real_path.ptr.pchar);
- fclose(fp);
- str_clean(&tmp.path);
- str_clean(&tmp.real_path);
- return NULL;
- }
- png_info = png_create_info_struct(png_read);
- if (! png_info) {
- err_write_1("gl_sprite_init: png_create_info_struct: ");
- err_puts(tmp.real_path.ptr.pchar);
- png_destroy_read_struct(&png_read, NULL, NULL);
- fclose(fp);
- str_clean(&tmp.path);
- str_clean(&tmp.real_path);
- return NULL;
- }
- gl_internal_format = 0;
- gl_format = 0;
- gl_type = 0;
- png_components = 0;
- if (setjmp(png_jmpbuf(png_read))) {
- png_destroy_read_struct(&png_read, &png_info, NULL);
- fclose(fp);
- str_clean(&tmp.path);
- str_clean(&tmp.real_path);
- return NULL;
- }
- png_set_sig_bytes(png_read, sizeof(png_header));
- png_init_io(png_read, fp);
- png_read_info(png_read, png_info);
- png_get_IHDR(png_read, png_info, &png_w, &png_h,
- &png_bit_depth, &png_color_type,
- NULL, NULL, NULL);
- if (png_color_type == PNG_COLOR_TYPE_PALETTE)
- png_set_palette_to_rgb(png_read);
- if (! png_info_to_gl_info(png_color_type, png_bit_depth, &gl_format,
- &gl_internal_format, &gl_type,
- &png_components)) {
- if (! gl_format || ! png_components) {
- err_write_1("gl_sprite_init: unknown PNG color type ");
- err_inspect_s32(&png_color_type);
- err_write_1(": ");
- err_puts(tmp.real_path.ptr.pchar);
- }
- if (! gl_internal_format) {
- err_write_1("gl_sprite_init: unknown OpenGL internal format: ");
- err_puts(tmp.real_path.ptr.pchar);
- }
- if (! gl_type) {
- err_write_1("gl_sprite_init: unknown OpenGL type: ");
- err_puts(tmp.real_path.ptr.pchar);
- }
- png_destroy_read_struct(&png_read, &png_info, NULL);
- fclose(fp);
- str_clean(&tmp.path);
- str_clean(&tmp.real_path);
- return NULL;
- }
- png_pixel_size = (png_bit_depth / 8) * png_components;
- if (! png_pixel_size)
- png_error(png_read, "unknown png pixel size");
- if (png_h > PNG_SIZE_MAX / (png_w * png_pixel_size))
- png_error(png_read, "image_data buffer would be too large");
- png_data = png_malloc(png_read, png_h * png_w * png_pixel_size);
- png_row = png_malloc(png_read, png_h * sizeof(png_bytep));
- i = 0;
- while (i < png_h) {
- png_row[i] = png_data + i * png_w * png_pixel_size;
- i++;
- }
- if (png_bit_depth < 8)
- png_set_packing(png_read);
- png_read_image(png_read, png_row);
- png_destroy_read_struct(&png_read, &png_info, NULL);
- fclose(fp);
- tmp.total_w = png_w;
- tmp.total_h = png_h;
- tmp.dim_x = dim_x;
- tmp.dim_y = dim_y;
- tmp.pix_w = tmp.total_w / dim_x;
- tmp.pix_h = tmp.total_h / dim_y;
- tmp.texture = calloc(tmp.frame_count, sizeof(GLuint));
- if (! tmp.texture) {
- err_puts("gl_sprite_init: tmp.texture:"
- " failed to allocate memory");
- str_clean(&tmp.path);
- str_clean(&tmp.real_path);
- return NULL;
- }
- assert(glGetError() == GL_NO_ERROR);
- glGenTextures(tmp.frame_count, tmp.texture);
- GLenum gl_error = glGetError();
- if (gl_error != GL_NO_ERROR) {
- err_write_1("gl_sprite_init: ");
- err_inspect_str(&tmp.real_path);
- err_write_1(": glGenTextures: ");
- err_puts(gl_error_string(gl_error));
- free(tmp.texture);
- str_clean(&tmp.path);
- str_clean(&tmp.real_path);
- return NULL;
- }
- sprite_stride = tmp.pix_w * png_pixel_size;
- data = malloc(tmp.pix_h * sprite_stride);
- if (! data) {
- err_write_1("gl_sprite_init: failed to allocate memory: ");
- err_puts(tmp.real_path.ptr.pchar);
- free(tmp.texture);
- str_clean(&tmp.path);
- str_clean(&tmp.real_path);
- return NULL;
- }
- glActiveTexture(GL_TEXTURE0);
- i = 0;
- y = 0;
- while (i < tmp.frame_count && y < dim_y) {
- x = 0;
- while (i < tmp.frame_count && x < dim_x) {
- sprite_data = data + sprite_stride * tmp.pix_h;
- v = 0;
- while (v < tmp.pix_h) {
- sprite_data -= sprite_stride;
- memcpy(sprite_data,
- png_row[y * tmp.pix_h + v] + x * sprite_stride,
- sprite_stride);
- v++;
- }
- glBindTexture(GL_TEXTURE_2D, tmp.texture[i]);
- gl_error = glGetError();
- if (gl_error != GL_NO_ERROR) {
- err_write_1("gl_sprite_init: ");
- err_inspect_str(&tmp.real_path);
- err_write_1(": glBindTexture: ");
- err_puts(gl_error_string(gl_error));
- return NULL;
- }
- 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_LINEAR_MIPMAP_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl_error = glGetError();
- if (gl_error != GL_NO_ERROR) {
- err_write_1("gl_sprite_init: ");
- err_inspect_str(&tmp.real_path);
- err_write_1(": glTexParameteri: ");
- err_puts(gl_error_string(gl_error));
- return NULL;
- }
- glTexImage2D(GL_TEXTURE_2D, 0, gl_format, tmp.pix_w, tmp.pix_h,
- 0, gl_format, gl_type, data);
- gl_error = glGetError();
- if (gl_error != GL_NO_ERROR) {
- err_write_1("gl_sprite_init: ");
- err_inspect_str(&tmp.real_path);
- err_write_1(": glTexImage2D: ");
- err_puts(gl_error_string(gl_error));
- return NULL;
- }
- glGenerateMipmap(GL_TEXTURE_2D);
- assert(glGetError() == GL_NO_ERROR);
- i++;
- x++;
- }
- y++;
- }
- glBindTexture(GL_TEXTURE_2D, 0);
- assert(glGetError() == GL_NO_ERROR);
- tmp.pt_w = tmp.pix_w * point_per_pixel;
- tmp.pt_h = tmp.pix_h * point_per_pixel;
- free(data);
- free(png_data);
- free(png_row);
- *sprite = tmp;
- return sprite;
-}
-
-GLuint gl_sprite_texture (const s_gl_sprite *sprite, uw frame)
-{
- assert(sprite);
- assert(frame < sprite->frame_count);
- frame %= sprite->frame_count;
- return sprite->texture[frame];
-}
diff --git a/libkc3_window/sdl2/gl_sprite.h b/libkc3_window/sdl2/gl_sprite.h
deleted file mode 100644
index a436f8d..0000000
--- a/libkc3_window/sdl2/gl_sprite.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 GL_SPRITE_H
-#define GL_SPRITE_H
-
-#include "types.h"
-
-/* Stack-allocation compatible functions, call gl_sprite_clean
- after use. */
-void gl_sprite_clean (s_gl_sprite *sprite);
-s_gl_sprite * gl_sprite_init (s_gl_sprite *sprite, const char *path,
- uw dim_x, uw dim_y, uw frame_count,
- f32 point_per_pixel);
-
-/* Observers. */
-GLuint gl_sprite_texture (const s_gl_sprite *sprite, uw frame);
-
-#endif /* GL_SPRITE_H */
diff --git a/libkc3_window/sdl2/gl_square.c b/libkc3_window/sdl2/gl_square.c
deleted file mode 100644
index 4b511cc..0000000
--- a/libkc3_window/sdl2/gl_square.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "gl_object.h"
-#include "vec3.h"
-#include "gl_square.h"
-
-void gl_square_clean (s_gl_square *square)
-{
- assert(square);
- gl_object_clean(&square->object);
-}
-
-void gl_square_delete (s_gl_square *square)
-{
- assert(square);
- gl_square_clean(square);
- free(square);
-}
-
-s_gl_square * gl_square_init (s_gl_square *square, uw seg_u, uw seg_v)
-{
- uw i;
- uw j;
- s_gl_square tmp = {0};
- s_gl_triangle *triangle;
- s_gl_vertex *vertex;
- f32 y;
- assert(square);
- if (seg_u < 2)
- seg_u = 2;
- if (seg_v < 2)
- seg_v = 2;
- tmp.segments_u = seg_u;
- tmp.segments_v = seg_v;
- if (! gl_object_init(&tmp.object) ||
- ! gl_object_allocate(&tmp.object, seg_u * seg_v,
- 2 * (seg_u - 1) * (seg_v - 1)))
- return NULL;
- vertex = tmp.object.vertex.data;
- i = 0;
- while (i < seg_v) {
- y = (f32) i / (seg_v - 1);
- j = 0;
- while (j < seg_u) {
- vertex->tex_coord_x = vertex->pos_x = (f32) j / (seg_u - 1);
- vertex->tex_coord_y = vertex->pos_y = y;
- vertex->pos_z = 0.0;
- vertex->normal_x = 0.0;
- vertex->normal_y = 0.0;
- vertex->normal_z = 1.0;
- vertex++;
- j++;
- }
- i++;
- }
- triangle = tmp.object.triangle.data;
- i = 0;
- while (i < seg_v - 1) {
- j = 0;
- while (j < seg_u - 1) {
- triangle->a = i * seg_u + j;
- triangle->b = (i + 1) * seg_u + j;
- triangle->c = (i + 1) * seg_u + j + 1;
- triangle++;
- triangle->a = i * seg_u + j;
- triangle->b = (i + 1) * seg_u + j + 1;
- triangle->c = i * seg_u + j + 1;
- triangle++;
- j++;
- }
- i++;
- }
- gl_object_update(&tmp.object);
- *square = tmp;
- return square;
-}
-
-s_gl_square * gl_square_new (uw segments_u, uw segments_v)
-{
- s_gl_square *square;
- square = calloc(1, sizeof(s_gl_square));
- if (! square) {
- err_puts("gl_square_new: failed to allocate memory");
- return NULL;
- }
- if (! gl_square_init(square, segments_u, segments_v)) {
- free(square);
- return NULL;
- }
- return square;
-}
-
-void gl_square_render (const s_gl_square *square)
-{
- assert(square);
- gl_object_render(&square->object);
-}
-
-void gl_square_render_wireframe (const s_gl_square *square)
-{
- assert(square);
- gl_object_render_wireframe(&square->object);
-}
diff --git a/libkc3_window/sdl2/gl_square.h b/libkc3_window/sdl2/gl_square.h
deleted file mode 100644
index 185d1cf..0000000
--- a/libkc3_window/sdl2/gl_square.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 GL_SQUARE_H
-#define GL_SQUARE_H
-
-#include "types.h"
-
-/* Stack-allocation compatible functions, call gl_square_clean after
- use. */
-void gl_square_clean (s_gl_square *square);
-s_gl_square * gl_square_init (s_gl_square *square, uw segments_u,
- uw segments_v);
-
-/* Heap-allocation functions, call gl_square_delete after use. */
-void gl_square_delete (s_gl_square *square);
-s_gl_square * gl_square_new (uw segments_u, uw segments_v);
-
-/* Observers. */
-void gl_square_render (const s_gl_square *square);
-void gl_square_render_wireframe (const s_gl_square *square);
-
-#endif /* GL_SQUARE_H */
diff --git a/libkc3_window/sdl2/gl_text.c b/libkc3_window/sdl2/gl_text.c
deleted file mode 100644
index 3bef988..0000000
--- a/libkc3_window/sdl2/gl_text.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "gl_text.h"
-#include "window_sdl2.h"
-
-void gl_text_clean (s_gl_text *text)
-{
- str_clean(&text->str);
- glDeleteTextures(1, &text->texture);
-}
-
-s_gl_text * gl_text_init (s_gl_text *text, const s_gl_font *font)
-{
- s_gl_text tmp = {0};
- assert(glGetError() == GL_NO_ERROR);
- tmp.font = font;
- glGenTextures(1, &tmp.texture);
- assert(glGetError() == GL_NO_ERROR);
- *text = tmp;
- return text;
-}
-
-s_gl_text * gl_text_init_1 (s_gl_text *text, const s_gl_font *font,
- const char *p)
-{
- s_str str;
- str_init_1(&str, NULL, p);
- return gl_text_init_str(text, font, &str);
-}
-
-s_gl_text * gl_text_init_str (s_gl_text *text, const s_gl_font *font,
- const s_str *str)
-{
- s_gl_text tmp = {0};
- if (! gl_text_init(&tmp, font))
- return NULL;
- if (! str_init_copy(&tmp.str, str))
- return NULL;
- *text = tmp;
- return text;
-}
-
-bool gl_text_render_to_texture (s_gl_text *text)
-{
- character c;
- u8 *data;
- uw data_w;
- uw data_h;
- u8 *data_pixel;
- uw data_size;
- uw data_x;
- uw data_y;
- FT_Vector delta;
- FT_Face face;
- const s_gl_font *font;
- FT_GlyphSlot glyph;
- FT_UInt glyph_index;
- uw i;
- uw j;
- uw line_height;
- uw max_ascent;
- uw max_descent;
- FT_UInt prev_glyph_index;
- s_str s;
- f32 scale_y;
- uw x;
- uw y;
- assert(text);
- assert(text->font);
- assert(text->texture);
- assert(glGetError() == GL_NO_ERROR);
- if (! text->str.size)
- return true;
- glBindTexture(GL_TEXTURE_2D, text->texture);
- assert(glGetError() == GL_NO_ERROR);
- font = text->font;
- face = font->ft_face;
- s = text->str;
- 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 = line_height;
- x = 0;
- prev_glyph_index = 0;
- while (str_read_character_utf8(&s, &c) > 0) {
- if (c == '\n') {
- if (x > data_w)
- data_w = x;
- x = 0;
- data_h += line_height;
- prev_glyph_index = 0;
- continue;
- }
- glyph_index = FT_Get_Char_Index(face, c);
- if (prev_glyph_index && glyph_index) {
- FT_Get_Kerning(face, prev_glyph_index, glyph_index,
- FT_KERNING_DEFAULT, &delta);
- x += delta.x >> 6;
- }
- if (FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER)) {
- err_write_1("gl_font_render_to_texture: failed to load glyph: ");
- err_inspect_character(&c);
- err_write_1("\n");
- continue;
- }
- glyph = face->glyph;
- x += glyph->metrics.horiAdvance >> 6;
- prev_glyph_index = glyph_index;
- }
- if (x > data_w)
- data_w = x;
- data_size = data_w * data_h * 4;
- data = calloc(1, data_size);
- x = 0;
- y = 0;
- prev_glyph_index = 0;
- s = text->str;
- while (str_read_character_utf8(&s, &c) > 0) {
- if (c == '\n') {
- x = 0;
- y += line_height;
- prev_glyph_index = 0;
- continue;
- }
- glyph_index = FT_Get_Char_Index(face, c);
- if (prev_glyph_index && glyph_index) {
- FT_Vector delta;
- FT_Get_Kerning(face, prev_glyph_index, glyph_index,
- FT_KERNING_DEFAULT, &delta);
- x += delta.x >> 6;
- }
- if (FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER))
- continue;
- glyph = face->glyph;
- i = 0;
- while (i < glyph->bitmap.rows) {
- data_y = data_h - 1 - (y + i + max_ascent - glyph->bitmap_top);
- //printf("\n");
- j = 0;
- while (j < glyph->bitmap.width) {
- data_x = x + j;
- data_pixel = data + (data_y * data_w + data_x) * 4;
- u8 value = glyph->bitmap.buffer[i * glyph->bitmap.width + j];
- 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]);
- j++;
- }
- i++;
- }
- x += glyph->metrics.horiAdvance >> 6;
- prev_glyph_index = glyph_index;
- }
- 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_text_set_font (s_gl_text *text, const s_gl_font *font)
-{
- assert(text);
- assert(font);
- if (text->font != font) {
- text->font = font;
- return true;
- }
- return false;
-}
-
-bool gl_text_set_text (s_gl_text *text, const s_str *str)
-{
- assert(text);
- assert(str);
- if (compare_str(&text->str, str)) {
- str_clean(&text->str);
- str_init_copy(&text->str, str);
- return true;
- }
- return false;
-}
-
-bool gl_text_set_text_1 (s_gl_text *text, const char *p)
-{
- s_str str;
- assert(text);
- assert(p);
- str_init_1(&str, NULL, p);
- return gl_text_set_text(text, &str);
-}
-
-bool gl_text_set_text_buf (s_gl_text *text, s_buf *buf)
-{
- bool result;
- s_str str;
- assert(text);
- assert(buf);
- buf_peek_to_str(buf, &str);
- result = gl_text_set_text(text, &str);
- str_clean(&str);
- return result;
-}
-
-bool gl_text_update (s_gl_text *text)
-{
- return gl_text_render_to_texture(text);
-}
-
-bool gl_text_update_1 (s_gl_text *text, const char *p)
-{
- if (gl_text_set_text_1(text, p)) {
- gl_text_update(text);
- return true;
- }
- return false;
-}
-
-bool gl_text_update_buf (s_gl_text *text, s_buf *buf)
-{
- if (gl_text_set_text_buf(text, buf)) {
- gl_text_update(text);
- return true;
- }
- return false;
-}
diff --git a/libkc3_window/sdl2/gl_text.h b/libkc3_window/sdl2/gl_text.h
deleted file mode 100644
index d4c9cd4..0000000
--- a/libkc3_window/sdl2/gl_text.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 GL_TEXT_H
-#define GL_TEXT_H
-
-#include "types.h"
-
-/* Stack-allocation compatible functions, call gl_text_clean
- after use. */
-void gl_text_clean (s_gl_text *text);
-s_gl_text * gl_text_init (s_gl_text *text, const s_gl_font *font);
-s_gl_text * gl_text_init_1 (s_gl_text *text, const s_gl_font *font,
- const char *p);
-s_gl_text * gl_text_init_str (s_gl_text *text, const s_gl_font *font,
- const s_str *str);
-
-/* Operators. */
-bool gl_text_render_to_texture (s_gl_text *text);
-bool gl_text_set_font (s_gl_text *text, const s_gl_font *font);
-bool gl_text_set_text (s_gl_text *text, const s_str *str);
-bool gl_text_set_text_1 (s_gl_text *text, const char *p);
-bool gl_text_set_text_buf (s_gl_text *text, s_buf *buf);
-bool gl_text_update (s_gl_text *text);
-bool gl_text_update_1 (s_gl_text *text, const char *p);
-bool gl_text_update_buf (s_gl_text *text, s_buf *buf);
-
-#endif /* GL_TEXT_H */
diff --git a/libkc3_window/sdl2/gl_triangle.c b/libkc3_window/sdl2/gl_triangle.c
deleted file mode 100644
index 0a346bd..0000000
--- a/libkc3_window/sdl2/gl_triangle.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "gl_triangle.h"
-
-s_gl_triangle * gl_triangle_init (s_gl_triangle *triangle, GLuint a,
- GLuint b, GLuint c)
-{
- assert(triangle);
- triangle->a = a;
- triangle->b = b;
- triangle->c = c;
- return triangle;
-}
diff --git a/libkc3_window/sdl2/gl_triangle.h b/libkc3_window/sdl2/gl_triangle.h
deleted file mode 100644
index 4e0333d..0000000
--- a/libkc3_window/sdl2/gl_triangle.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 GL_TRIANGLE_H
-#define GL_TRIANGLE_H
-
-#include "types.h"
-
-s_gl_triangle * gl_triangle_init (s_gl_triangle *triangle, GLuint a,
- GLuint b, GLuint c);
-
-#endif /* GL_TRIANGLE_H */
diff --git a/libkc3_window/sdl2/gl_vertex.c b/libkc3_window/sdl2/gl_vertex.c
deleted file mode 100644
index ea82997..0000000
--- a/libkc3_window/sdl2/gl_vertex.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "mat4.h"
-#include "vec3.h"
-#include "gl_vertex.h"
-
-void gl_vertex_attrib (void)
-{
- assert(glGetError() == GL_NO_ERROR);
- glEnableVertexAttribArray(0);
- assert(glGetError() == GL_NO_ERROR);
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(s_gl_vertex),
- (void *) 0);
- assert(glGetError() == GL_NO_ERROR);
- glEnableVertexAttribArray(1);
- assert(glGetError() == GL_NO_ERROR);
- glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(s_gl_vertex),
- (void *) (3 * sizeof(float)));
- assert(glGetError() == GL_NO_ERROR);
- glEnableVertexAttribArray(2);
- assert(glGetError() == GL_NO_ERROR);
- glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(s_gl_vertex),
- (void *) (6 * sizeof(float)));
- assert(glGetError() == GL_NO_ERROR);
-}
-
-void gl_vertex_transform (s_gl_vertex *vertex, const s_mat4 *matrix)
-{
- assert(vertex);
- assert(matrix);
- mat4_mult_vec3(matrix, (s_vec3 *) &vertex->pos_x,
- (s_vec3 *) &vertex->pos_x);
- mat4_mult_vec3(matrix, (s_vec3 *) &vertex->normal_x,
- (s_vec3 *) &vertex->normal_x);
- vec3_normalize((s_vec3 *) &vertex->normal_x);
-}
diff --git a/libkc3_window/sdl2/gl_vertex.h b/libkc3_window/sdl2/gl_vertex.h
deleted file mode 100644
index 7206048..0000000
--- a/libkc3_window/sdl2/gl_vertex.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 GL_VERTEX_H
-#define GL_VERTEX_H
-
-#include "types.h"
-
-void gl_vertex_attrib (void);
-void gl_vertex_transform (s_gl_vertex *vertex, const s_mat4 *matrix);
-
-#endif /* GL_VERTEX_H */
diff --git a/libkc3_window/sdl2/gl_vtext.c b/libkc3_window/sdl2/gl_vtext.c
deleted file mode 100644
index 3927976..0000000
--- a/libkc3_window/sdl2/gl_vtext.c
+++ /dev/null
@@ -1,403 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "gl_vtext.h"
-
-void gl_vtext_clean (s_gl_text *text)
-{
- assert(text);
- str_clean(&text->str);
- glDeleteTextures(1, &text->texture);
-}
-
-void gl_vtext_delete (s_gl_text *text)
-{
- gl_vtext_clean(text);
- free(text);
-}
-
-s_gl_text * gl_vtext_init (s_gl_text *text, const s_gl_font *font)
-{
- s_gl_text tmp = {0};
- assert(glGetError() == GL_NO_ERROR);
- tmp.font = font;
- glGenTextures(1, &tmp.texture);
- assert(glGetError() == GL_NO_ERROR);
- *text = tmp;
- return text;
-}
-
-s_gl_text * gl_vtext_init_1 (s_gl_text *text, const s_gl_font *font,
- const char *p)
-{
- s_str str;
- str_init_1(&str, NULL, p);
- return gl_vtext_init_str(text, font, &str);
-}
-
-s_gl_text * gl_vtext_init_str (s_gl_text *text, const s_gl_font *font,
- const s_str *str)
-{
- s_gl_text tmp = {0};
- if (! gl_vtext_init(&tmp, font))
- return NULL;
- if (! str_init_copy(&tmp.str, str))
- return NULL;
- *text = tmp;
- 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;
- text = calloc(1, sizeof(s_gl_text));
- if (! text) {
- err_puts("gl_vtext_new_1: failed to allocate memory");
- assert(! "gl_vtext_new_1: failed to allocate memory");
- return NULL;
- }
- if (! gl_vtext_init_1(text, font, p)) {
- free(text);
- return NULL;
- }
- return text;
-}
-
-s_gl_text * gl_vtext_new_str (const s_gl_font *font, const s_str *str)
-{
- s_gl_text *text;
- text = calloc(1, sizeof(s_gl_text));
- if (! text) {
- err_puts("gl_vtext_new_1: failed to allocate memory");
- assert(! "gl_vtext_new_1: failed to allocate memory");
- return NULL;
- }
- if (! gl_vtext_init_str(text, font, str)) {
- free(text);
- return NULL;
- }
- return text;
-}
-
-bool gl_vtext_render_to_texture (s_gl_text *text)
-{
- character c;
- 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 line_height;
- uw max_ascent;
- uw max_descent;
- s_str s;
- f32 scale_y;
- uw x;
- uw y;
- assert(text);
- assert(text->font);
- assert(text->texture);
- assert(glGetError() == GL_NO_ERROR);
- if (! text->str.size)
- return true;
- glBindTexture(GL_TEXTURE_2D, text->texture);
- assert(glGetError() == GL_NO_ERROR);
- font = text->font;
- face = font->ft_face;
- s = text->str;
- 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;
- while (str_read_character_utf8(&s, &c) > 0) {
- glyph_index = FT_Get_Char_Index(face, c);
- if (FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER)) {
- err_write_1("gl_font_render_to_texture: failed to load glyph: ");
- err_inspect_character(&c);
- 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;
- s = text->str;
- while (str_read_character_utf8(&s, &c) > 0) {
- glyph_index = FT_Get_Char_Index(face, c);
- if (FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER))
- continue;
- glyph = face->glyph;
- x = (data_w - (glyph->metrics.width >> 6)) / 2;
- i = 0;
- while (i < glyph->bitmap.rows) {
- data_y = data_h - line_height - 1 - (y + i + max_ascent - glyph->bitmap_top);
- //printf("\n");
- j = 0;
- while (j < glyph->bitmap.width) {
- data_x = x + j;
- data_pixel = data + (data_y * data_w + data_x) * 4;
- u8 value = glyph->bitmap.buffer[i * glyph->bitmap.width + j];
- 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]);
- j++;
- }
- i++;
- }
- 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_render_to_texture_random (s_gl_text *text, uw len)
-{
- FT_UInt *glyphs;
- u8 *data;
- sw data_w;
- sw data_h;
- u8 *data_pixel;
- sw data_size;
- sw data_x;
- sw data_y;
- FT_Face face;
- const s_gl_font *font;
- FT_GlyphSlot glyph;
- FT_UInt glyph_index;
- sw i;
- uw j;
- uw k;
- sw line_height;
- sw max_ascent;
- sw max_descent;
- f32 scale_y;
- sw x;
- sw 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 (glyphs)");
- assert(! "gl_vtext_render_to_texture_random:"
- " failed to allocate memory (glyphs)");
- return false;
- }
- for (i = 0; i < (sw) len; i++) {
- glyph = NULL;
- 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 >> 6);
- } while (! glyph || ! (glyph->metrics.width >> 6));
- }
- 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 < (sw) 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_w++;
- data_h += line_height * 2;
- data_size = data_w * data_h * 4;
- data = calloc(1, data_size);
- if (! data) {
- err_puts("gl_vtext_render_to_texture_random:"
- " failed to allocate memory (data)");
- assert(! "gl_vtext_render_to_texture_random:"
- " failed to allocate memory (data)");
- free(glyphs);
- return false;
- }
- x = 0;
- y = 0;
- for (i = 0; i < (sw) 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 - line_height - 1 -
- ((sw) 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;
- }
- free(glyphs);
- 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);
- assert(font);
- if (text->font != font) {
- text->font = font;
- return true;
- }
- return false;
-}
-
-bool gl_vtext_set_text (s_gl_text *text, const s_str *str)
-{
- assert(text);
- assert(str);
- if (compare_str(&text->str, str)) {
- str_clean(&text->str);
- str_init_copy(&text->str, str);
- return true;
- }
- return false;
-}
-
-bool gl_vtext_set_text_1 (s_gl_text *text, const char *p)
-{
- s_str str;
- assert(text);
- assert(p);
- str_init_1(&str, NULL, p);
- return gl_vtext_set_text(text, &str);
-}
-
-bool gl_vtext_set_text_buf (s_gl_text *text, s_buf *buf)
-{
- bool result;
- s_str str;
- assert(text);
- assert(buf);
- buf_peek_to_str(buf, &str);
- result = gl_vtext_set_text(text, &str);
- str_clean(&str);
- return result;
-}
-
-bool gl_vtext_update (s_gl_text *text)
-{
- return gl_vtext_render_to_texture(text);
-}
-
-bool gl_vtext_update_1 (s_gl_text *text, const char *p)
-{
- if (gl_vtext_set_text_1(text, p)) {
- gl_vtext_update(text);
- return true;
- }
- return false;
-}
-
-bool gl_vtext_update_buf (s_gl_text *text, s_buf *buf)
-{
- if (gl_vtext_set_text_buf(text, buf)) {
- gl_vtext_update(text);
- return true;
- }
- return false;
-}
diff --git a/libkc3_window/sdl2/gl_vtext.h b/libkc3_window/sdl2/gl_vtext.h
deleted file mode 100644
index 82d67d7..0000000
--- a/libkc3_window/sdl2/gl_vtext.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 GL_VTEXT_H
-#define GL_VTEXT_H
-
-#include "types.h"
-
-/* Stack-allocation compatible functions, call gl_vtext_clean
- after use. */
-void gl_vtext_clean (s_gl_text *text);
-s_gl_text * gl_vtext_init (s_gl_text *text, const s_gl_font *font);
-s_gl_text * gl_vtext_init_1 (s_gl_text *text, const s_gl_font *font,
- const char *p);
-s_gl_text * gl_vtext_init_str (s_gl_text *text, const s_gl_font *font,
- const s_str *str);
-
-/* 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);
-bool gl_vtext_set_text_buf (s_gl_text *text, s_buf *buf);
-bool gl_vtext_update (s_gl_text *text);
-bool gl_vtext_update_1 (s_gl_text *text, const char *p);
-bool gl_vtext_update_buf (s_gl_text *text, s_buf *buf);
-
-#endif /* GL_TEXT_H */
diff --git a/libkc3_window/sdl2/mat3.h b/libkc3_window/sdl2/mat3.h
deleted file mode 100644
index a48b057..0000000
--- a/libkc3_window/sdl2/mat3.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 MAT3_H
-#define MAT3_H
-
-#include "types.h"
-
-/* Stack-allocation compatible functions. */
-s_mat3 * mat3_init_copy (s_mat3 *m, const s_mat3 *src);
-s_mat3 * mat3_init_identity (s_mat3 *m);
-s_mat3 * mat3_init_matrix_mult (s_mat3 *m, const s_mat3 *a,
- const s_mat3 *b);
-
-/* Heap-allocation functions, call mat3_delete after use. */
-void mat3_delete (s_mat3 *m);
-s_mat3 * mat3_new_copy (const s_mat3 *src);
-s_mat3 * mat3_new_identity (void);
-s_mat3 * mat3_new_matrix_mult (const s_mat3 *a, const s_mat3 *b);
-
-/* Operators. */
-s_mat3 * mat3_rotate (s_mat3 *m, f32 rad);
-s_mat3 * mat3_scale (s_mat3 *m, f32 x, f32 y);
-s_mat3 * mat3_translate (s_mat3 *m, f32 x, f32 y);
-
-#endif /* MAT3_H */
diff --git a/libkc3_window/sdl2/mat4.c b/libkc3_window/sdl2/mat4.c
deleted file mode 100644
index 3272eb8..0000000
--- a/libkc3_window/sdl2/mat4.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "mat4.h"
-#include "vec3.h"
-
-sw mat4_buf_inspect (s_buf *buf, const s_mat4 *matrix)
-{
- u8 i;
- u8 j;
- sw r;
- sw result = 0;
- assert(buf);
- assert(matrix);
- const f32 *m;
- if ((r = buf_write_1(buf, "(F32) {")) < 0)
- return r;
- result += r;
- m = &matrix->xx;
- i = 0;
- while (i < 4) {
- j = 0;
- while (j < 4) {
- if ((r = buf_inspect_f32(buf, m + j * 4 + i)) < 0)
- return r;
- result += r;
- if (i < 3 || j < 3) {
- if ((r = buf_write_1(buf, ",")) < 0)
- return r;
- result += r;
- if (j < 3) {
- if ((r = buf_write_1(buf, " ")) < 0)
- return r;
- result += r;
- }
- }
- j++;
- }
- if (i < 3) {
- if ((r = buf_write_1(buf, "\n ")) < 0)
- return r;
- result += r;
- }
- i++;
- }
- if ((r = buf_write_1(buf, "}\n")) < 0)
- return r;
- result += r;
- return result;
-}
-
-s_mat4 * mat4_init_copy (s_mat4 *m, const s_mat4 *src)
-{
- assert(m);
- assert(src);
- *m = *src;
- return m;
-}
-
-s_mat4 * mat4_init_ortho (s_mat4 *m, f32 x1, f32 x2, f32 y1, f32 y2,
- f32 clip_z_near, f32 clip_z_far)
-{
- f32 dx;
- f32 dy;
- f32 dz;
- s_mat4 ortho;
- assert(m);
- dx = x2 - x1;
- dy = y2 - y1;
- dz = clip_z_far - clip_z_near;
- mat4_init_zero(&ortho);
- ortho.xx = 2.0 / dx;
- ortho.yy = 2.0 / dy;
- ortho.zz = -2.0 / dz;
- ortho.tx = - (x1 + x2) / dx;
- ortho.ty = - (y1 + y2) / dy;
- ortho.tz = - (clip_z_near + clip_z_far) / dz;
- ortho.tt = 1.0;
- *m = ortho;
- return m;
-}
-
-s_mat4 * mat4_init_product (s_mat4 *m, const s_mat4 *a, const s_mat4 *b)
-{
- assert(m);
- assert(a);
- assert(b);
- m->xx = a->xx * b->xx + a->xy * b->yx + a->xz * b->zx + a->xt * b->tx;
- m->xy = a->xx * b->xy + a->xy * b->yy + a->xz * b->zy + a->xt * b->ty;
- m->xz = a->xx * b->xz + a->xy * b->yz + a->xz * b->zz + a->xt * b->tz;
- m->xt = a->xx * b->xt + a->xy * b->yt + a->xz * b->zt + a->xt * b->tt;
- m->yx = a->yx * b->xx + a->yy * b->yx + a->yz * b->zx + a->yt * b->tx;
- m->yy = a->yx * b->xy + a->yy * b->yy + a->yz * b->zy + a->yt * b->ty;
- m->yz = a->yx * b->xz + a->yy * b->yz + a->yz * b->zz + a->yt * b->tz;
- m->yt = a->yx * b->xt + a->yy * b->yt + a->yz * b->zt + a->yt * b->tt;
- m->zx = a->zx * b->xx + a->zy * b->yx + a->zz * b->zx + a->zt * b->tx;
- m->zy = a->zx * b->xy + a->zy * b->yy + a->zz * b->zy + a->zt * b->ty;
- m->zz = a->zx * b->xz + a->zy * b->yz + a->zz * b->zz + a->zt * b->tz;
- m->zt = a->zx * b->xt + a->zy * b->yt + a->zz * b->zt + a->zt * b->tt;
- m->tx = a->tx * b->xx + a->ty * b->yx + a->tz * b->zx + a->tt * b->tx;
- m->ty = a->tx * b->xy + a->ty * b->yy + a->tz * b->zy + a->tt * b->ty;
- m->tz = a->tx * b->xz + a->ty * b->yz + a->tz * b->zz + a->tt * b->tz;
- m->tt = a->tx * b->xt + a->ty * b->yt + a->tz * b->zt + a->tt * b->tt;
- return m;
-}
-
-s_mat4 * mat4_init_identity (s_mat4 *m)
-{
- assert(m);
- m->xx = 1.0; m->xy = 0.0; m->xz = 0.0; m->xt = 0.0;
- m->yx = 0.0; m->yy = 1.0; m->yz = 0.0; m->yt = 0.0;
- m->zx = 0.0; m->zy = 0.0; m->zz = 1.0; m->zt = 0.0;
- m->tx = 0.0; m->ty = 0.0; m->tz = 0.0; m->tt = 1.0;
- return m;
-}
-
-s_mat4 * mat4_init_scale (s_mat4 *m, f32 x, f32 y, f32 z)
-{
- assert(m);
- m->xx = x; m->xy = 0.0; m->xz = 0.0; m->xt = 0.0;
- m->yx = 0.0; m->yy = y; m->yz = 0.0; m->yt = 0.0;
- m->zx = 0.0; m->zy = 0.0; m->zz = z; m->zt = 0.0;
- m->tx = 0.0; m->ty = 0.0; m->tz = 0.0; m->tt = 1.0;
- return m;
-}
-
-s_mat4 * mat4_init_zero (s_mat4 *m)
-{
- assert(m);
- m->xx = 0.0; m->xy = 0.0; m->xz = 0.0; m->xt = 0.0;
- m->yx = 0.0; m->yy = 0.0; m->yz = 0.0; m->yt = 0.0;
- m->zx = 0.0; m->zy = 0.0; m->zz = 0.0; m->zt = 0.0;
- m->tx = 0.0; m->ty = 0.0; m->tz = 0.0; m->tt = 0.0;
- return m;
-}
-
-void mat4_delete (s_mat4 *m)
-{
- free(m);
-}
-
-s_mat4 * mat4_new_copy (const s_mat4 *src)
-{
- s_mat4 *m;
- m = calloc(1, sizeof(s_mat4));
- if (! m) {
- err_puts("mat4_new: failed to allocate memory");
- return NULL;
- }
- *m = *src;
- return m;
-}
-
-s_mat4 * mat4_new_product (const s_mat4 *a, const s_mat4 *b)
-{
- s_mat4 *m;
- assert(a);
- assert(b);
- m = calloc(1, sizeof(s_mat4));
- if (! m) {
- err_puts("mat4_new: failed to allocate memory");
- return NULL;
- }
- mat4_init_product(m, a, b);
- return m;
-}
-
-s_mat4 * mat4_new_zero (void)
-{
- s_mat4 *m;
- m = calloc(1, sizeof(s_mat4));
- if (! m) {
- err_puts("mat4_new: failed to allocate memory");
- return NULL;
- }
- mat4_init_zero(m);
- return m;
-}
-
-s_mat4 * mat4_ortho (s_mat4 *m, f32 x1, f32 x2, f32 y1, f32 y2,
- f32 clip_z_near, f32 clip_z_far)
-{
- s_mat4 ortho;
- assert(m);
- mat4_init_ortho(&ortho, x1, x2, y1, y2, clip_z_near, clip_z_far);
- return mat4_mult_mat4(&ortho, m, m);
-}
-
-s_mat4 * mat4_perspective (s_mat4 *m, f32 fov_y,
- f32 aspect_ratio,
- f32 z_near,
- f32 z_far)
-{
- f32 dz;
- s_mat4 perspective;
- f32 f;
- f32 fov_y_2;
- fov_y_2 = fov_y / 2.0;
- f = cos(fov_y_2) / sin(fov_y_2);
- dz = z_near - z_far;
- mat4_init_zero(&perspective);
- perspective.xx = f / aspect_ratio;
- perspective.yy = f;
- perspective.zz = (z_near + z_far) / dz;
- perspective.zt = -1.0;
- perspective.tz = 2.0 * z_near * z_far / dz;
- return mat4_mult_mat4(&perspective, m, m);
-}
-
-s_mat4 * mat4_mult_mat4 (const s_mat4 *a, const s_mat4 *b, s_mat4 *dest)
-{
- s_mat4 m;
- assert(a);
- assert(b);
- m.xx = a->xx * b->xx + a->xy * b->yx + a->xz * b->zx + a->xt * b->tx;
- m.xy = a->xx * b->xy + a->xy * b->yy + a->xz * b->zy + a->xt * b->ty;
- m.xz = a->xx * b->xz + a->xy * b->yz + a->xz * b->zz + a->xt * b->tz;
- m.xt = a->xx * b->xt + a->xy * b->yt + a->xz * b->zt + a->xt * b->tt;
- m.yx = a->yx * b->xx + a->yy * b->yx + a->yz * b->zx + a->yt * b->tx;
- m.yy = a->yx * b->xy + a->yy * b->yy + a->yz * b->zy + a->yt * b->ty;
- m.yz = a->yx * b->xz + a->yy * b->yz + a->yz * b->zz + a->yt * b->tz;
- m.yt = a->yx * b->xt + a->yy * b->yt + a->yz * b->zt + a->yt * b->tt;
- m.zx = a->zx * b->xx + a->zy * b->yx + a->zz * b->zx + a->zt * b->tx;
- m.zy = a->zx * b->xy + a->zy * b->yy + a->zz * b->zy + a->zt * b->ty;
- m.zz = a->zx * b->xz + a->zy * b->yz + a->zz * b->zz + a->zt * b->tz;
- m.zt = a->zx * b->xt + a->zy * b->yt + a->zz * b->zt + a->zt * b->tt;
- m.tx = a->tx * b->xx + a->ty * b->yx + a->tz * b->zx + a->tt * b->tx;
- m.ty = a->tx * b->xy + a->ty * b->yy + a->tz * b->zy + a->tt * b->ty;
- m.tz = a->tx * b->xz + a->ty * b->yz + a->tz * b->zz + a->tt * b->tz;
- m.tt = a->tx * b->xt + a->ty * b->yt + a->tz * b->zt + a->tt * b->tt;
- *dest = m;
- return dest;
-}
-
-s_mat4 * mat4_scale (s_mat4 *m, f32 x, f32 y, f32 z)
-{
- s_mat4 s;
- mat4_init_zero(&s);
- s.xx = x;
- s.yy = y;
- s.zz = z;
- s.tt = 1.0;
- return mat4_mult_mat4(&s, m, m);
-}
-
-s_mat4 * mat4_translate (s_mat4 *m, f32 x, f32 y, f32 z)
-{
- s_mat4 s;
- mat4_init_identity(&s);
- s.tx = x;
- s.ty = y;
- s.tz = z;
- return mat4_mult_mat4(&s, m, m);
-}
-
-s_mat4 * mat4_rotate_axis (s_mat4 *m, f32 rad, const s_vec3 *axis)
-{
- s_vec3 a;
- f32 angle;
- f32 one_minus_x;
- f32 x;
- f32 y;
- vec3_init_normalize(&a, axis);
- angle = -rad;
- x = cosf(angle);
- one_minus_x = 1.0 - x;
- y = sinf(angle);
- s_mat4 r = { x + a.x * a.x * one_minus_x,
- a.x * a.y * one_minus_x - a.z * y,
- a.x * a.z * one_minus_x + a.y * y,
- 0.0,
- a.x * a.y * one_minus_x + a.z * y,
- x + a.y * a.y * one_minus_x,
- a.y * a.z * one_minus_x - a.x * y,
- 0.0,
- a.x * a.z * one_minus_x - a.y * y,
- a.y * a.z * one_minus_x + a.x * y,
- x + a.z * a.z * one_minus_x,
- 0.0,
- 0.0, 0.0, 0.0, 1.0 };
- return mat4_mult_mat4(&r, m, m);
-}
diff --git a/libkc3_window/sdl2/mat4.h b/libkc3_window/sdl2/mat4.h
deleted file mode 100644
index 00fedf1..0000000
--- a/libkc3_window/sdl2/mat4.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 MAT4_H
-#define MAT4_H
-
-#include "types.h"
-
-/* Stack-allocation compatible functions. */
-s_mat4 * mat4_init_copy (s_mat4 *m, const s_mat4 *src);
-s_mat4 * mat4_init_identity (s_mat4 *m);
-s_mat4 * mat4_init_product (s_mat4 *m, const s_mat4 *a,
- const s_mat4 *b);
-s_mat4 * mat4_init_scale (s_mat4 *m, f32 x, f32 y, f32 z);
-s_mat4 * mat4_init_zero (s_mat4 *m);
-
-/* Heap-allocation functions, call mat4_delete after use. */
-void mat4_delete (s_mat4 *m);
-s_mat4 * mat4_new_copy (const s_mat4 *src);
-s_mat4 * mat4_new_identity (void);
-s_mat4 * mat4_new_matrix_mult (const s_mat4 *a, const s_mat4 *b);
-s_mat4 * mat4_new_zero (void);
-
-/* Operators. */
-s_mat4 * mat4_mult_mat4 (const s_mat4 *a, const s_mat4 *b, s_mat4 *dest);
-s_vec3 * mat4_mult_vec3 (const s_mat4 *a, const s_vec3 *b, s_vec3 *dest);
-s_mat4 * mat4_ortho (s_mat4 *m, f32 x1, f32 x2, f32 y1, f32 y2,
- f32 clip_z_near, f32 clip_z_far);
-s_mat4 * mat4_perspective (s_mat4 *m, f32 fov_y, f32 aspect_ratio,
- f32 clip_z_near, f32 clip_z_far);
-s_mat4 * mat4_rotate_axis (s_mat4 *m, f32 rad, const s_vec3 *axis);
-s_mat4 * mat4_scale (s_mat4 *m, f32 x, f32 y, f32 z);
-s_mat4 * mat4_translate (s_mat4 *m, f32 x, f32 y, f32 z);
-
-/* Observers. */
-sw mat4_buf_inspect (s_buf *buf, const s_mat4 *matrix);
-
-#endif /* MAT4_H */
diff --git a/libkc3_window/sdl2/sources.mk b/libkc3_window/sdl2/sources.mk
deleted file mode 100644
index bb0e664..0000000
--- a/libkc3_window/sdl2/sources.mk
+++ /dev/null
@@ -1,50 +0,0 @@
-# sources.mk generated by update_sources
-HEADERS = \
- "dmat3.h" \
- "dmat4.h" \
- "dvec2.h" \
- "dvec3.h" \
- "gl_camera.h" \
- "gl_cylinder.h" \
- "gl_deprecated.h" \
- "gl_font.h" \
- "gl_lines.h" \
- "gl_object.h" \
- "gl_ortho.h" \
- "gl_sphere.h" \
- "gl_sprite.h" \
- "gl_square.h" \
- "gl_text.h" \
- "gl_triangle.h" \
- "gl_vertex.h" \
- "gl_vtext.h" \
- "mat3.h" \
- "mat4.h" \
- "types.h" \
- "vec2.h" \
- "vec3.h" \
- "window_sdl2.h" \
-
-SOURCES = \
- "dmat4.c" \
- "dvec2.c" \
- "dvec3.c" \
- "gl_camera.c" \
- "gl_cylinder.c" \
- "gl_deprecated.c" \
- "gl_font.c" \
- "gl_lines.c" \
- "gl_object.c" \
- "gl_ortho.c" \
- "gl_sphere.c" \
- "gl_sprite.c" \
- "gl_square.c" \
- "gl_text.c" \
- "gl_triangle.c" \
- "gl_vertex.c" \
- "gl_vtext.c" \
- "mat4.c" \
- "vec2.c" \
- "vec3.c" \
- "window_sdl2.c" \
-
diff --git a/libkc3_window/sdl2/sources.sh b/libkc3_window/sdl2/sources.sh
deleted file mode 100644
index 9c93345..0000000
--- a/libkc3_window/sdl2/sources.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-# sources.sh generated by update_sources
-HEADERS='dmat3.h dmat4.h dvec2.h dvec3.h gl_camera.h gl_cylinder.h gl_deprecated.h gl_font.h gl_lines.h gl_object.h gl_ortho.h gl_sphere.h gl_sprite.h gl_square.h gl_text.h gl_triangle.h gl_vertex.h gl_vtext.h mat3.h mat4.h types.h vec2.h vec3.h window_sdl2.h '
-SOURCES='dmat4.c dvec2.c dvec3.c gl_camera.c gl_cylinder.c gl_deprecated.c gl_font.c gl_lines.c gl_object.c gl_ortho.c gl_sphere.c gl_sprite.c gl_square.c gl_text.c gl_triangle.c gl_vertex.c gl_vtext.c mat4.c vec2.c vec3.c window_sdl2.c '
diff --git a/libkc3_window/sdl2/types.h b/libkc3_window/sdl2/types.h
deleted file mode 100644
index 6b6952e..0000000
--- a/libkc3_window/sdl2/types.h
+++ /dev/null
@@ -1,396 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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.
- */
-/** @file types.h
- * @brief Module KC3.Window.SDL2
- *
- * Struct for all GUI window SDL2 graphics operations.
- */
-#ifndef LIBKC3_WINDOW_SDL2_TYPES_H
-#define LIBKC3_WINDOW_SDL2_TYPES_H
-
-#include <GL/glew.h>
-#include <SDL.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include <png.h>
-#include <libkc3/types.h>
-#include "../types.h"
-
-#define GL_CAMERA_LIGHT_MAX 16 // keep in sync with shader
-
-typedef struct dmat3 s_dmat3;
-typedef struct dmat4 s_dmat4;
-typedef struct dvec2 s_dvec2;
-typedef struct dvec3 s_dvec3;
-typedef struct dvec4 s_dvec4;
-typedef struct gl_camera s_gl_camera;
-typedef struct gl_cylinder s_gl_cylinder;
-typedef struct gl_font s_gl_font;
-typedef struct gl_light s_gl_light;
-typedef struct gl_lines s_gl_lines;
-typedef struct gl_material s_gl_material;
-typedef struct gl_object s_gl_object;
-typedef struct gl_ortho s_gl_ortho;
-typedef struct gl_sphere s_gl_sphere;
-typedef struct gl_sprite s_gl_sprite;
-typedef struct gl_square s_gl_square;
-typedef struct gl_text s_gl_text;
-typedef struct gl_triangle s_gl_triangle;
-typedef struct gl_vertex s_gl_vertex;
-typedef struct mat3 s_mat3;
-typedef struct mat4 s_mat4;
-typedef struct rgb s_rgb;
-typedef struct rgba s_rgba;
-typedef struct vec2 s_vec2;
-typedef struct vec3 s_vec3;
-typedef struct vec4 s_vec4;
-typedef struct window_sdl2 s_window_sdl2;
-
-/* return false to break event loop */
-typedef bool (*f_window_sdl2_button) (s_window_sdl2 *window,
- u8 button, sw x, sw y);
-
-/* return false to break event loop */
-typedef bool (*f_window_sdl2_key) (s_window_sdl2 *window,
- SDL_Keysym *keysym);
-
-/* return false to break event loop */
-typedef bool (*f_window_sdl2_load) (s_window_sdl2 *window);
-
-/* return false to break event loop */
-typedef bool (*f_window_sdl2_motion) (s_window_sdl2 *window, sw x,
- sw y);
-
-/* return false to break event loop */
-typedef bool (*f_window_sdl2_render) (s_window_sdl2 *window);
-
-/* return false to break event loop */
-typedef bool (*f_window_sdl2_resize) (s_window_sdl2 *window,
- uw w, uw h);
-
-typedef bool (*f_window_sdl2_sequence_load) (s_sequence *seq,
- s_window_sdl2 *window);
-
-typedef bool (*f_window_sdl2_sequence_render) (s_sequence *seq,
- s_window_sdl2 *window,
- void *context);
-
-typedef void (*f_window_sdl2_unload) (s_window_sdl2 *window);
-
-/* 1 */
-
-struct dmat3 {
- f64 xx;
- f64 yx;
- f64 zx;
- f64 xy;
- f64 yy;
- f64 zy;
- f64 xz;
- f64 yz;
- f64 zz;
-};
-
-struct dmat4 {
- f64 xx;
- f64 xy;
- f64 xz;
- f64 xt;
- f64 yx;
- f64 yy;
- f64 yz;
- f64 yt;
- f64 zx;
- f64 zy;
- f64 zz;
- f64 zt;
- f64 tx;
- f64 ty;
- f64 tz;
- f64 tt;
-};
-
-struct dvec2 {
- f64 x;
- f64 y;
-};
-
-struct dvec3 {
- f64 x;
- f64 y;
- f64 z;
-};
-
-struct dvec4 {
- f64 x;
- f64 y;
- f64 z;
- f64 t;
-};
-
-struct gl_font {
- FT_Face ft_face;
- s_str path;
- f32 point_size;
- f32 point_per_pixel;
- s_str real_path;
-};
-
-struct gl_lines {
- s_array vertex;
- GLuint gl_vao;
- GLuint gl_vbo;
-};
-
-struct mat3 {
- f32 xx;
- f32 yx;
- f32 zx;
- f32 xy;
- f32 yy;
- f32 zy;
- f32 xz;
- f32 yz;
- f32 zz;
-};
-
-struct mat4 {
- f32 xx;
- f32 xy;
- f32 xz;
- f32 xt;
- f32 yx;
- f32 yy;
- f32 yz;
- f32 yt;
- f32 zx;
- f32 zy;
- f32 zz;
- f32 zt;
- f32 tx;
- f32 ty;
- f32 tz;
- f32 tt;
-};
-
-struct gl_object {
- s_array vertex;
- s_array triangle;
- u32 gl_mode;
- u32 gl_vao;
- u32 gl_vbo;
- u32 gl_ebo;
-};
-
-struct gl_sprite {
- uw dim_x;
- uw dim_y;
- uw frame_count;
- s_str path;
- uw pix_w;
- uw pix_h;
- f32 pt_w;
- f32 pt_h;
- s_str real_path;
- GLuint *texture;
- uw total_w;
- uw total_h;
-};
-
-struct gl_text {
- const s_gl_font *font;
- uw pix_w;
- uw pix_h;
- f32 pt_w;
- f32 pt_h;
- s_str str;
- GLuint texture;
-};
-
-struct gl_triangle {
- GLuint a;
- GLuint b;
- GLuint c;
-};
-
-struct rgb {
- f32 r;
- f32 g;
- f32 b;
-};
-
-struct rgba {
- f32 r;
- f32 g;
- f32 b;
- f32 a;
-};
-
-struct vec2 {
- f32 x;
- f32 y;
-};
-
-struct vec3 {
- f32 x;
- f32 y;
- f32 z;
-};
-
-struct vec4 {
- f32 x;
- f32 y;
- f32 z;
- f32 t;
-};
-
-/* Subtype of s_window. See libkc3/window/types.h */
-struct window_sdl2 {
- sw x;
- sw y;
- uw w;
- uw h;
- bool fullscreen;
- f_window_sdl2_button button;
- f_window_sdl2_key key;
- f_window_sdl2_load load;
- f_window_sdl2_motion motion;
- f_window_sdl2_render render;
- SDL_Window *sdl_window;
- f_window_sdl2_resize resize;
- s_sequence *seq;
- s_sequence *sequence;
- uw sequence_count;
- uw sequence_pos;
- s_tag tag; // TODO: move sequence to tag
- const char *title;
- f_window_sdl2_unload unload;
- uw gl_w;
- uw gl_h;
- float dpi;
- float dpi_w;
- float dpi_h;
-};
-
-/* 2 */
-
-struct gl_cylinder {
- s_gl_object object;
- uw segments_u;
- uw segments_v;
-};
-
-struct gl_light {
- s_vec4 position; // in camera coordinates
- s_rgb intensity;
-};
-
-struct gl_material {
- f32 roughness;
- bool metal;
- s_rgba color;
-};
-
-struct gl_sphere {
- s_gl_object object;
- uw segments_u;
- uw segments_v;
-};
-
-struct gl_square {
- s_gl_object object;
- uw segments_u;
- uw segments_v;
-};
-
-struct gl_vertex {
- f32 pos_x;
- f32 pos_y;
- f32 pos_z;
- f32 normal_x;
- f32 normal_y;
- f32 normal_z;
- f32 tex_coord_x;
- f32 tex_coord_y;
-};
-
-struct sdl2_sprite {
- s_gl_object object;
- s_str path;
- s_str real_path;
- uw total_w;
- uw total_h;
- uw dim_x;
- uw dim_y;
- uw frame_count;
- uw w;
- uw h;
- uw tex_w;
- uw tex_h;
- GLuint *texture;
-};
-
-/* 3 */
-
-struct gl_camera {
- f32 aspect_ratio;
- f32 clip_z_far;
- f32 clip_z_near;
- f32 fov_y;
- s_vec3 position;
- s_vec3 rotation;
- s_vec3 scale;
- s_mat4 projection_matrix;
- s_mat4 view_matrix;
- s_mat4 model_matrix;
- GLint light_count;
- s_vec3 light_pos[GL_CAMERA_LIGHT_MAX];
- s_vec3 light_pos_cam[GL_CAMERA_LIGHT_MAX];
- s_rgb light_color[GL_CAMERA_LIGHT_MAX];
- GLuint gl_projection_matrix_loc;
- GLuint gl_view_matrix_loc;
- GLuint gl_model_matrix_loc;
- GLuint gl_enable_tex2d_loc;
- GLuint gl_tex2d_loc;
- GLuint gl_light_pos_loc;
- GLuint gl_light_color_loc;
- GLuint gl_material_rough_loc;
- GLuint gl_material_metal_loc;
- GLuint gl_material_color_loc;
- GLuint gl_shader_program;
-};
-
-struct gl_ortho {
- f32 x1;
- f32 x2;
- f32 y1;
- f32 y2;
- f32 clip_z_near;
- f32 clip_z_far;
- s_vec3 position;
- s_vec3 rotation;
- s_vec3 scale;
- s_mat4 projection_matrix;
- GLuint gl_projection_matrix_loc;
- s_mat4 view_matrix;
- GLuint gl_view_matrix_loc;
- s_mat4 model_matrix;
- GLuint gl_model_matrix_loc;
- GLuint gl_enable_tex2d_loc;
- GLuint gl_tex2d_loc;
- GLuint gl_color_loc;
- GLuint gl_shader_program;
- s_gl_square square;
-};
-
-#endif /* LIBKC3_WINDOW_SDL2_TYPES_H */
diff --git a/libkc3_window/sdl2/update_sources b/libkc3_window/sdl2/update_sources
deleted file mode 100755
index 7375817..0000000
--- a/libkc3_window/sdl2/update_sources
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-. ../../config.subr
-
-echo "$PWD/update_sources"
-
-echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
-echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
-
-HEADERS="$(ls *.h | grep -v '^config.h$')"
-sources HEADERS "$HEADERS"
-
-SOURCES="$(ls *.c)"
-sources SOURCES "$SOURCES"
-
-update_sources_mk
-update_sources_sh
-
-( cd demo && ./update_sources; )
diff --git a/libkc3_window/sdl2/vec2.c b/libkc3_window/sdl2/vec2.c
deleted file mode 100644
index 75b4f46..0000000
--- a/libkc3_window/sdl2/vec2.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "vec2.h"
-
-s_vec2 * vec2_init (s_vec2 *p, f32 x, f32 y)
-{
- assert(p);
- p->x = x;
- p->y = y;
- return p;
-}
-
-s_vec2 * vec2_init_copy (s_vec2 *p, const s_vec2 *src)
-{
- assert(p);
- assert(src);
- p->x = src->x;
- p->y = src->y;
- return p;
-}
-
-s_vec2 *
-vec2_init_product (s_vec2 *p, const s_mat3 *m, const s_vec2 *s)
-{
- assert(p);
- assert(m);
- assert(s);
- p->x = s->x * m->xx + s->y * m->xy + m->xz;
- p->y = s->x * m->yx + s->y * m->yy + m->yz;
- return p;
-}
-
-s_vec2 * vec2_init_zero (s_vec2 *p)
-{
- assert(p);
- p->x = 0.0;
- p->y = 0.0;
- return p;
-}
-
-void vec2_delete (s_vec2 *p)
-{
- free(p);
-}
-
-s_vec2 * vec2_new (f32 x, f32 y)
-{
- s_vec2 *p;
- p = calloc(1, sizeof(s_vec2));
- if (! p) {
- err_puts("vec2_new: failed to allocate memory");
- return NULL;
- }
- vec2_init(p, x, y);
- return p;
-}
-
-s_vec2 * vec2_new_copy (const s_vec2 *src)
-{
- s_vec2 *p;
- p = calloc(1, sizeof(s_vec2));
- if (! p) {
- err_puts("vec2_new: failed to allocate memory");
- return NULL;
- }
- vec2_init_copy(p, src);
- return p;
-}
-
-s_vec2 * vec2_new_zero (void)
-{
- s_vec2 *p;
- p = calloc(1, sizeof(s_vec2));
- if (! p) {
- err_puts("vec2_new: failed to allocate memory");
- return NULL;
- }
- vec2_init_zero(p);
- return p;
-}
diff --git a/libkc3_window/sdl2/vec2.h b/libkc3_window/sdl2/vec2.h
deleted file mode 100644
index f975dc4..0000000
--- a/libkc3_window/sdl2/vec2.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 VEC2_H
-#define VEC2_H
-
-#include "types.h"
-
-/* Stack-allocation compatible functions. */
-s_vec2 * vec2_init (s_vec2 *p, f32 x, f32 y);
-s_vec2 * vec2_init_copy (s_vec2 *p, const s_vec2 *src);
-s_vec2 * vec2_init_product (s_vec2 *p, const s_mat3 *m,
- const s_vec2 *s);
-s_vec2 * vec2_init_zero (s_vec2 *p);
-
-/* Heap-allocation functions, call vec2_delete after use. */
-void vec2_delete (s_vec2 *p);
-s_vec2 * vec2_new (f32 x, f32 y);
-s_vec2 * vec2_new_copy (const s_vec2 *src);
-s_vec2 * vec2_new_product (const s_mat3 *m, const s_vec2 *s);
-s_vec2 * vec2_new_zero (void);
-
-#endif /* VEC2_H */
diff --git a/libkc3_window/sdl2/vec3.c b/libkc3_window/sdl2/vec3.c
deleted file mode 100644
index 1421a75..0000000
--- a/libkc3_window/sdl2/vec3.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "vec3.h"
-
-s_vec3 * vec3_init (s_vec3 *p, f32 x, f32 y, f32 z)
-{
- assert(p);
- p->x = x;
- p->y = y;
- p->z = z;
- return p;
-}
-
-s_vec3 * vec3_init_copy (s_vec3 *p, const s_vec3 *src)
-{
- assert(p);
- assert(src);
- p->x = src->x;
- p->y = src->y;
- p->z = src->z;
- return p;
-}
-
-s_vec3 * vec3_init_normalize (s_vec3 *p, const s_vec3 *src)
-{
- f32 norm;
- f32 ratio;
- assert(p);
- assert(src);
- norm = vec3_norm(src);
- ratio = 1.0f / norm;
- p->x = src->x * ratio;
- p->y = src->y * ratio;
- p->z = src->z * ratio;
- return p;
-}
-
-s_vec3 * mat4_mult_vec3 (const s_mat4 *a, const s_vec3 *b, s_vec3 *dest)
-{
- assert(a);
- assert(b);
- assert(dest);
- dest->x = a->xx * b->x + a->xy * b->y + a->xz * b->z + a->xt;
- dest->y = a->yx * b->x + a->yy * b->y + a->yz * b->z + a->yt;
- dest->z = a->zx * b->x + a->zy * b->y + a->zz * b->z + a->zt;
- return dest;
-}
-
-s_vec3 * vec3_init_zero (s_vec3 *p)
-{
- assert(p);
- p->x = 0.0;
- p->y = 0.0;
- p->z = 0.0;
- return p;
-}
-
-void vec3_delete (s_vec3 *p)
-{
- free(p);
-}
-
-s_vec3 * vec3_new (f32 x, f32 y, f32 z)
-{
- s_vec3 *p;
- p = calloc(1, sizeof(s_vec3));
- if (! p) {
- err_puts("vec3_new: failed to allocate memory");
- return NULL;
- }
- vec3_init(p, x, y, z);
- return p;
-}
-
-s_vec3 * vec3_new_copy (const s_vec3 *src)
-{
- s_vec3 *p;
- p = calloc(1, sizeof(s_vec3));
- if (! p) {
- err_puts("vec3_new: failed to allocate memory");
- return NULL;
- }
- vec3_init_copy(p, src);
- return p;
-}
-
-s_vec3 * vec3_new_zero (void)
-{
- s_vec3 *p;
- p = calloc(1, sizeof(s_vec3));
- if (! p) {
- err_puts("vec3_new: failed to allocate memory");
- return NULL;
- }
- vec3_init_zero(p);
- return p;
-}
-
-f32 vec3_norm (const s_vec3 *p)
-{
- assert(p);
- return sqrtf(p->x * p->x + p->y * p->y + p->z * p->z);
-}
-
-void vec3_normalize (s_vec3 *p)
-{
- f32 norm;
- f32 ratio;
- assert(p);
- norm = vec3_norm(p);
- ratio = 1.0f / norm;
- p->x *= ratio;
- p->y *= ratio;
- p->z *= ratio;
-}
diff --git a/libkc3_window/sdl2/vec3.h b/libkc3_window/sdl2/vec3.h
deleted file mode 100644
index 0224588..0000000
--- a/libkc3_window/sdl2/vec3.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 VEC3_H
-#define VEC3_H
-
-#include "types.h"
-
-/* Stack-allocation compatible functions. */
-s_vec3 * vec3_init (s_vec3 *p, f32 x, f32 y, f32 z);
-s_vec3 * vec3_init_copy (s_vec3 *p, const s_vec3 *src);
-s_vec3 * vec3_init_normalize (s_vec3 *p, const s_vec3 *src);
-s_vec3 * vec3_init_zero (s_vec3 *p);
-
-/* Heap-allocation functions, call vec3_delete after use. */
-void vec3_delete (s_vec3 *p);
-s_vec3 * vec3_new (f32 x, f32 y, f32 z);
-s_vec3 * vec3_new_copy (const s_vec3 *src);
-s_vec3 * vec3_new_zero (void);
-
-/* Operators. */
-void vec3_normalize (s_vec3 *p);
-
-/* Observers. */
-f32 vec3_norm (const s_vec3 *p);
-
-#endif /* VEC3_H */
diff --git a/libkc3_window/sdl2/window_sdl2.c b/libkc3_window/sdl2/window_sdl2.c
deleted file mode 100644
index fa02a9b..0000000
--- a/libkc3_window/sdl2/window_sdl2.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <err.h>
-#include <stdlib.h>
-#include <xkbcommon/xkbcommon.h>
-#include <libkc3/kc3.h>
-#include "../window.h"
-#include "gl_deprecated.h"
-#include "window_sdl2.h"
-
-const char *g_gray_3_bits_utf8[] = {
- " ", ".", ":", "#", "░", "▒", "▓", "█"
-};
-
-static bool g_window_sdl2_initialized = false;
-
-static void gl_debug (GLenum source, GLenum type, GLuint id,
- GLenum severity, GLsizei length,
- const GLchar* message, const void* user_param)
-{
- (void) source;
- (void) type;
- (void) id;
- (void) severity;
- (void) length;
- (void) user_param;
- err_write_1("gl_debug_callback: ");
- err_puts(message);
-}
-
-void window_sdl2_clean (s_window_sdl2 *window)
-{
- window_clean((s_window *) window);
-}
-
-bool window_sdl2_default_button_cb (s_window_sdl2 *window, u8 button,
- sw x, sw y)
-{
- assert(window);
- (void) window;
- (void) button;
- (void) x;
- (void) y;
- printf("window_sdl2_default_button_cb: %d (%ld, %ld)\n",
- (int) button, x, y);
- return true;
-}
-
-bool window_sdl2_default_key_cb (s_window_sdl2 *window,
- SDL_Keysym *keysym)
-{
- assert(window);
- assert(keysym);
- (void) window;
- (void) keysym;
- printf("window_sdl2_default_key_cb: %d\n", keysym->sym);
- return true;
-}
-
-bool window_sdl2_default_load_cb (s_window_sdl2 *window)
-{
- assert(window);
- (void) window;
- printf("window_sdl2_default_load_cb\n");
- return true;
-}
-
-bool window_sdl2_default_motion_cb (s_window_sdl2 *window, sw x, sw y)
-{
- assert(window);
- (void) window;
- (void) x;
- (void) y;
- /*
- printf("window_sdl2_default_motion_cb (%ld, %ld)\n", x, y);
- */
- return true;
-}
-
-bool window_sdl2_default_render_cb (s_window_sdl2 *window)
-{
- assert(window);
- (void) window;
- printf("window_sdl2_default_render_cb\n");
- return true;
-}
-
-bool window_sdl2_default_resize_cb (s_window_sdl2 *window, uw w, uw h)
-{
- assert(window);
- (void) window;
- (void) w;
- (void) h;
- printf("window_sdl2_default_resize_cb: %lu x %lu\n", w, h);
- return true;
-}
-
-void window_sdl2_default_unload_cb (s_window_sdl2 *window)
-{
- assert(window);
- (void) window;
- printf("window_sdl2_default_unload_cb\n");
-}
-
-s_window_sdl2 * window_sdl2_init (s_window_sdl2 *window,
- sw x, sw y, uw w, uw h,
- const char *title,
- uw sequence_count)
-{
- s_window_sdl2 tmp = {0};
- assert(window);
- title = title ? title : "KC3.Window.Sdl2";
- window_init((s_window *) &tmp, x, y, w, h, title, sequence_count);
- tmp.button = window_sdl2_default_button_cb;
- tmp.key = window_sdl2_default_key_cb;
- tmp.load = window_sdl2_default_load_cb;
- tmp.motion = window_sdl2_default_motion_cb;
- tmp.render = window_sdl2_default_render_cb;
- tmp.resize = window_sdl2_default_resize_cb;
- tmp.unload = window_sdl2_default_unload_cb;
- *window = tmp;
- return window;
-}
-
-bool window_sdl2_run (s_window_sdl2 *window)
-{
- SDL_GLContext context;
- int mouse_x, mouse_y;
- int quit = 0;
- SDL_Event sdl_event;
- SDL_Window *sdl_window;
- assert(window);
- if (! g_window_sdl2_initialized) {
- //SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1");
- if (SDL_Init(SDL_INIT_VIDEO)) {
- warnx("window_sdl2_run: SDL initialization failed: %s",
- SDL_GetError());
- return false;
- }
- g_window_sdl2_initialized = true;
- }
- if (SDL_VideoInit(NULL)) {
- warnx("window_sdl2_run: SDL_VideoInit failed: %s",
- SDL_GetError());
- return false;
- }
- SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
- SDL_GL_CONTEXT_PROFILE_CORE);
- sdl_window = SDL_CreateWindow(window->title,
- window->x, window->y,
- window->w, window->h,
- SDL_WINDOW_ALLOW_HIGHDPI |
- SDL_WINDOW_OPENGL |
- SDL_WINDOW_RESIZABLE |
- SDL_WINDOW_SHOWN);
- if (! sdl_window) {
- warnx("window_sdl2_run: failed to create window: %s",
- SDL_GetError());
- return false;
- }
- SDL_SetWindowBordered(sdl_window, SDL_TRUE);
- window->sdl_window = sdl_window;
- context = SDL_GL_CreateContext(sdl_window);
- if (! context) {
- warnx("window_sdl2_run: failed to create OpenGL context: %s",
- SDL_GetError());
- return false;
- }
- GLenum gl_error = glGetError();
- if (gl_error != GL_NO_ERROR) {
- warnx("OpenGL initialization error: %s\n",
- gl_error_string(gl_error));
- goto ko;
- }
- glewExperimental = GL_TRUE;
- if (glewInit() != GLEW_OK) {
- warnx("window_sdl2_run: failed to initialize GLEW");
- goto ko;
- }
- const char * version = (const char *) glGetString(GL_VERSION);
- if (version) {
- err_write_1("window_sdl2_run: OpenGL Version: ");
- err_puts(version);
- } else {
- err_puts("window_sdl2_run: failed to retrieve OpenGL version");
- goto ko;
- }
- if (glDebugMessageCallback) {
- glEnable(GL_DEBUG_OUTPUT);
- glDebugMessageCallback((GLDEBUGPROC) gl_debug, NULL);
- }
- if (SDL_GL_MakeCurrent(sdl_window, context) < 0) {
- warnx("window_sdl2_run: failed to make OpenGL context current: %s",
- SDL_GetError());
- goto ko;
- }
- int gl_w = window->w;
- int gl_h = window->h;
- SDL_GL_GetDrawableSize(sdl_window, &gl_w, &gl_h);
- window->gl_w = gl_w;
- window->gl_h = gl_h;
- int display_index;
- display_index = SDL_GetWindowDisplayIndex(sdl_window);
- if (display_index < 0) {
- err_write_1("window_sdl2_run: failed to get display index: ");
- err_puts(SDL_GetError());
- goto ko;
- }
- if (SDL_GetDisplayDPI(display_index, &window->dpi, &window->dpi_w,
- &window->dpi_h) != 0) {
- err_write_1("window_sdl2_run: failed to get display DPI: ");
- err_puts(SDL_GetError());
- goto ko;
- }
- fprintf(stderr, "window_sdl2_run: dpi=%.2f, dpi_w=%.2f, dpi_h=%.2f\n",
- window->dpi, window->dpi_w, window->dpi_h);
- SDL_GL_SetSwapInterval(1);
- assert(glGetError() == GL_NO_ERROR);
- if (! window->load(window)) {
- err_puts("window_sdl2_run: window->load => false");
- goto ko;
- }
- assert(glGetError() == GL_NO_ERROR);
- while (! quit) {
- assert(glGetError() == GL_NO_ERROR);
- while (SDL_PollEvent(&sdl_event) != 0) {
- assert(glGetError() == GL_NO_ERROR);
- switch (sdl_event.type) {
- case SDL_QUIT:
- err_puts("window_sdl2_run: SDL_QUIT");
- quit = 1;
- break;
- case SDL_KEYDOWN:
- if (! window->key(window, &sdl_event.key.keysym)) {
- err_puts("window_sdl2_run: window->key => false");
- quit = 1;
- }
- break;
- case SDL_MOUSEBUTTONDOWN:
- if (! window->button(window, sdl_event.button.button,
- sdl_event.button.x, sdl_event.button.y)) {
- err_puts("window_sdl2_run: window->button => false");
- quit = 1;
- }
- break;
- case SDL_MOUSEWHEEL:
- SDL_GetMouseState(&mouse_x, &mouse_y);
- if (! window->button(window, sdl_event.wheel.y > 0 ? 4 : 5,
- mouse_x, mouse_y)) {
- err_puts("window_sdl2_run: window->button => false");
- quit = 1;
- }
- break;
- case SDL_MOUSEMOTION:
- //int relativeX = sdl_event.motion.xrel;
- //int relativeY = sdl_event.motion.yrel;
- if (! window->motion(window, sdl_event.motion.x,
- sdl_event.motion.y)) {
- err_puts("window_sdl2_run: window->motion => false");
- quit = 1;
- }
- break;
- case SDL_WINDOWEVENT:
- if (sdl_event.window.event == SDL_WINDOWEVENT_RESIZED) {
- if (! window->resize(window, sdl_event.window.data1,
- sdl_event.window.data2)) {
- err_puts("window_sdl2_run: window->resize => false");
- quit = 1;
- }
- assert(glGetError() == GL_NO_ERROR);
- window->w = sdl_event.window.data1;
- window->h = sdl_event.window.data2;
- SDL_GL_GetDrawableSize(sdl_window, &gl_w, &gl_h);
- assert(glGetError() == GL_NO_ERROR);
- window->gl_w = gl_w;
- window->gl_h = gl_h;
- glViewport(0, 0, gl_w, gl_h);
- }
- break;
- default:
- break;
- }
- }
- assert(glGetError() == GL_NO_ERROR);
- //glDrawBuffer(GL_BACK);
- if (! window->render(window)) {
- err_puts("window_sdl2_run: window->render => false");
- quit = 1;
- }
- SDL_GL_SwapWindow(sdl_window);
- }
- SDL_GL_DeleteContext(context);
- SDL_DestroyWindow(sdl_window);
- return true;
- ko:
- SDL_GL_DeleteContext(context);
- SDL_DestroyWindow(sdl_window);
- return false;
-}
diff --git a/libkc3_window/sdl2/window_sdl2.h b/libkc3_window/sdl2/window_sdl2.h
deleted file mode 100644
index ed80fc1..0000000
--- a/libkc3_window/sdl2/window_sdl2.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_SDL2_H
-#define LIBKC3_WINDOW_SDL2_H
-
-#include "types.h"
-
-extern const char *g_gray_3_bits_utf8[];
-
-/* Stack-allocation compatible functions, call window_sdl2_clean
- after use. */
-void window_sdl2_clean (s_window_sdl2 *window);
-s_window_sdl2 * window_sdl2_init (s_window_sdl2 *window,
- sw x, sw y, uw w, uw h,
- const char *title,
- uw sequence_count);
-
-/* Operators. */
-bool window_sdl2_run (s_window_sdl2 *window);
-
-/* Callbacks. */
-bool window_sdl2_default_button_cb (s_window_sdl2 *window, u8 button,
- sw x, sw y);
-bool window_sdl2_default_key_cb (s_window_sdl2 *window,
- SDL_Keysym *keysym);
-bool window_sdl2_default_load_cb (s_window_sdl2 *window);
-bool window_sdl2_default_motion_cb (s_window_sdl2 *window, sw x, sw y);
-bool window_sdl2_default_render_cb (s_window_sdl2 *window);
-bool window_sdl2_default_resize_cb (s_window_sdl2 *window, uw w, uw h);
-void window_sdl2_default_unload_cb (s_window_sdl2 *window);
-
-#endif /* LIBKC3_WINDOW_SDL2_H */
diff --git a/libkc3_window/sources.mk b/libkc3_window/sources.mk
deleted file mode 100644
index 990366e..0000000
--- a/libkc3_window/sources.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-# sources.mk generated by update_sources
-HEADERS = \
- "types.h" \
- "window.h" \
-
-SOURCES = \
- "window.c" \
-
diff --git a/libkc3_window/sources.sh b/libkc3_window/sources.sh
deleted file mode 100644
index 8a6bfbb..0000000
--- a/libkc3_window/sources.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-# sources.sh generated by update_sources
-HEADERS='types.h window.h '
-SOURCES='window.c '
diff --git a/libkc3_window/types.h b/libkc3_window/types.h
deleted file mode 100644
index b2e7e59..0000000
--- a/libkc3_window/types.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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.
- */
-/** @file types.h
- * @brief Module C3.Window
- *
- * Base struct for all GUI window operations.
- */
-#ifndef LIBKC3_WINDOW_TYPES_H
-#define LIBKC3_WINDOW_TYPES_H
-
-#include <libkc3/types.h>
-
-typedef struct window s_window;
-
-/* return false to break event loop */
-typedef bool (*f_window_button) (s_window *window, u8 button,
- uw x, uw y);
-
-/* return false to break event loop */
-typedef bool (*f_window_key) (s_window *window, uw sym);
-
-/* return false to break event loop */
-typedef bool (*f_window_load) (s_window *window);
-
-/* return false to break event loop */
-typedef bool (*f_window_motion) (s_window *window, sw x, sw y);
-
-/* return false to break event loop */
-typedef bool (*f_window_render) (s_window *window);
-
-/* return false to break event loop */
-typedef bool (*f_window_resize) (s_window *window,
- uw w, uw h);
-
-typedef void (*f_window_unload) (s_window *window);
-
-/* To subtype make a copy of this struct while replacing
- * pointer types (including pointer to function types).
- * E.g. see libkc3/window/cairo/types.h */
-struct window {
- sw x;
- sw y;
- uw w;
- uw h;
- bool fullscreen;
- f_window_button button;
- f_window_key key;
- f_window_load load;
- f_window_motion motion;
- f_window_render render;
- void *context;
- f_window_resize resize;
- s_sequence *seq;
- s_sequence *sequence;
- uw sequence_count;
- uw sequence_pos;
- s_tag tag; // TODO: move sequence to tag
- const char *title;
- f_window_unload unload;
-};
-
-#endif /* LIBKC3_WINDOW_TYPES_H */
diff --git a/libkc3_window/update_sources b/libkc3_window/update_sources
deleted file mode 100755
index c7c9b07..0000000
--- a/libkc3_window/update_sources
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/sh
-## kc3
-## Copyright 2022-2024 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.
-
-. ../config.subr
-
-echo "$PWD/update_sources"
-
-echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
-echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
-
-HEADERS="$(ls *.h | grep -v '^config.h$')"
-sources HEADERS "$HEADERS"
-
-SOURCES="$(ls *.c)"
-sources SOURCES "$SOURCES"
-
-update_sources_mk
-update_sources_sh
-
-( cd cairo && ./update_sources; )
-( cd sdl2 && ./update_sources; )
diff --git a/libkc3_window/window.c b/libkc3_window/window.c
deleted file mode 100644
index 19f60e8..0000000
--- a/libkc3_window/window.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
-#include "window.h"
-
-bool window_animate (s_window *window)
-{
- s_timespec clock_monotonic;
- s_timespec delta;
- s_sequence *seq;
- f64 t;
- if (clock_gettime(CLOCK_MONOTONIC, &clock_monotonic)) {
- err_puts("window_animate: clock_gettime");
- return false;
- }
- if (window->sequence_pos >= window->sequence_count) {
- err_puts("window_animate: window->sequence_pos >="
- " window->sequence_count");
- return false;
- }
- seq = window->sequence + window->sequence_pos;
- time_sub(&clock_monotonic, &seq->t0, &delta);
- time_to_f64(&delta, &t);
- seq->dt = t - seq->t;
- seq->frame++;
- seq->t = t;
- /* printf("window_animate: %f\n", t); */
- if (t > seq->duration &&
- ! window_set_sequence_pos(window, (window->sequence_pos + 1) %
- window->sequence_count))
- return false;
- return true;
-}
-
-void window_clean (s_window *window)
-{
- uw i;
- assert(window);
- i = 0;
- if (window->seq && window->seq->unload)
- window->seq->unload(window->seq);
- while (i < window->sequence_count) {
- sequence_clean(window->sequence + i);
- i++;
- }
- free(window->sequence);
- tag_clean(&window->tag);
- window->unload(window);
-}
-
-s_window * window_init (s_window *window,
- sw x, sw y, uw w, uw h,
- const char *title,
- uw sequence_count)
-{
- s_window tmp = {0};
- assert(window);
- tmp.x = x;
- tmp.y = y;
- tmp.w = w;
- tmp.h = h;
- tmp.sequence = calloc(sequence_count, sizeof(s_sequence));
- tmp.sequence_count = sequence_count;
- tmp.sequence_pos = 0;
- tag_init_void(&tmp.tag);
- tmp.title = title ? title : "KC3.Window";
- *window = tmp;
- return window;
-}
-
-bool window_set_sequence_pos (s_window *window, uw sequence_pos)
-{
- s_sequence *seq;
- assert(window);
- printf("window_set_sequence_pos %lu\n", sequence_pos);
- if (sequence_pos >= window->sequence_count)
- return false;
- seq = window->sequence + sequence_pos;
- seq->dt = 0.0;
- seq->frame = 0;
- seq->t = 0.0;
- if (clock_gettime(CLOCK_MONOTONIC, &seq->t0)) {
- err_puts("window_set_sequence_pos: clock_gettime");
- return false;
- }
- window->sequence_pos = sequence_pos;
- if (window->seq)
- if (! window->seq->unload(window->seq))
- return false;
- window->seq = seq;
- io_puts(seq->title);
- if (! seq->load(seq))
- return false;
- return true;
-}
diff --git a/libkc3_window/window.h b/libkc3_window/window.h
deleted file mode 100644
index 0e0a796..0000000
--- a/libkc3_window/window.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* kc3
- * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_H
-#define LIBKC3_WINDOW_H
-
-#include <libkc3/types.h>
-#include "types.h"
-
-/* Stack-allocation compatible functions, call window_clean
- after use. */
-void window_clean (s_window *window);
-s_window * window_init (s_window *window,
- sw x, sw y, uw w, uw h,
- const char *title,
- uw sequence_count);
-
-/* Operators. */
-bool window_animate (s_window *window);
-bool window_set_sequence_pos (s_window *window, uw sequence_pos);
-
-#endif /* LIBKC3_WINDOW_H */
diff --git a/update_sources b/update_sources
index 2759a04..7906425 100755
--- a/update_sources
+++ b/update_sources
@@ -79,12 +79,12 @@ sources KC3_EXTERNAL_SOURCES "$KC3_EXTERNAL_SOURCES"
update_sources_mk
update_sources_sh
-( cd libtommath && ./update_sources; )
-( cd libkc3 && ./update_sources; )
-( cd ikc3 && ./update_sources; )
-( cd kc3s && ./update_sources; )
-( cd ekc3 && ./update_sources; )
-( cd http && ./update_sources; )
-( cd httpd && ./update_sources; )
-( cd test && ./update_sources; )
-( cd libkc3_window && ./update_sources; )
+( cd libtommath && ./update_sources; )
+( cd libkc3 && ./update_sources; )
+( cd ikc3 && ./update_sources; )
+( cd kc3s && ./update_sources; )
+( cd ekc3 && ./update_sources; )
+( cd http && ./update_sources; )
+( cd httpd && ./update_sources; )
+( cd test && ./update_sources; )
+( cd window && ./update_sources; )
diff --git a/window/Makefile b/window/Makefile
new file mode 100644
index 0000000..c7fac7c
--- /dev/null
+++ b/window/Makefile
@@ -0,0 +1,132 @@
+## kc3
+## Copyright 2022-2024 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.
+
+all:
+ ${MAKE} build
+ ${MAKE} debug
+ if ${HAVE_ASAN}; then ${MAKE} asan; fi
+ if ${HAVE_GCOV}; then ${MAKE} cov; fi
+
+asan:
+ ${MAKE} ${LIB_ASAN}
+ if ${HAVE_CAIRO}; then ${MAKE} -C cairo asan; fi
+ if ${HAVE_SDL2}; then ${MAKE} -C sdl2 asan; fi
+
+build:
+ ${MAKE} ${LIB}
+ if ${HAVE_CAIRO}; then ${MAKE} -C cairo build; fi
+ if ${HAVE_SDL2}; then ${MAKE} -C sdl2 build; fi
+
+clean:
+ if ${HAVE_CAIRO}; then ${MAKE} -C cairo clean; fi
+ if ${HAVE_SDL2}; then ${MAKE} -C sdl2 clean; fi
+
+clean_cov:
+ if ${HAVE_CAIRO}; then ${MAKE} -C cairo clean_cov; fi
+ if ${HAVE_SDL2}; then ${MAKE} -C sdl2 clean_cov; fi
+
+cov:
+ ${MAKE} ${LIB_COV}
+ if ${HAVE_CAIRO}; then ${MAKE} -C cairo cov; fi
+ if ${HAVE_SDL2}; then ${MAKE} -C sdl2 cov; fi
+
+debug:
+ ${MAKE} ${LIB_DEBUG}
+ if ${HAVE_CAIRO}; then ${MAKE} -C cairo debug; fi
+ if ${HAVE_SDL2}; then ${MAKE} -C sdl2 debug; fi
+
+demo: build
+ if ${HAVE_CAIRO}; then ${MAKE} -C cairo demo; fi
+
+demo_asan: asan
+ if ${HAVE_CAIRO}; then ${MAKE} -C cairo demo_asan; fi
+
+demo_cov: cov
+ if ${HAVE_CAIRO}; then ${MAKE} -C cairo demo_cov; fi
+
+demo_debug: debug
+ if ${HAVE_CAIRO}; then ${MAKE} -C cairo demo_debug; fi
+
+demo_gl: build
+ if ${HAVE_SDL2}; then ${MAKE} -C sdl2 demo; fi
+
+demo_gl_asan: asan
+ if ${HAVE_SDL2}; then ${MAKE} -C sdl2 demo_asan; fi
+
+demo_gl_cov: cov
+ if ${HAVE_SDL2}; then ${MAKE} -C sdl2 demo_cov; fi
+
+demo_gl_debug: debug
+ if ${HAVE_SDL2}; then ${MAKE} -C sdl2 demo_debug; fi
+
+distclean:
+ if ${HAVE_CAIRO}; then ${MAKE} -C cairo distclean; fi
+ if ${HAVE_SDL2}; then ${MAKE} -C sdl2 distclean; fi
+
+gcovr:
+ if ${HAVE_CAIRO}; then ${MAKE} -C cairo gcovr; fi
+ if ${HAVE_SDL2}; then ${MAKE} -C sdl2 gcovr; fi
+
+gdb_demo: debug
+ if ${HAVE_CAIRO}; then ${MAKE} -C cairo gdb_demo; fi
+
+gdb_demo_gl: debug
+ if ${HAVE_SDL2}; then ${MAKE} -C sdl2 gdb_demo; fi
+
+install:
+ ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0755 -d ${prefix}/include/libkc3/window
+ ${LIBTOOL} --tag=CC --mode=install ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0644 ${HEADERS} ${prefix}/include/libkc3/window
+ ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0755 -d ${prefix}/lib
+ ${LIBTOOL} --tag=CC --mode=install ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0644 ${LIB} ${prefix}/lib
+ ${LIBTOOL} --finish ${prefix}/lib
+ if ${HAVE_CAIRO}; then ${MAKE} -C cairo install; fi
+ if ${HAVE_SDL2}; then ${MAKE} -C sdl2 install; fi
+
+lldb_demo: debug
+ if ${HAVE_CAIRO}; then ${MAKE} -C cairo lldb_demo; fi
+
+lldb_demo_gl: debug
+ if ${HAVE_SDL2}; then ${MAKE} -C sdl2 lldb_demo; fi
+
+test:
+ if ${HAVE_CAIRO}; then ${MAKE} -C cairo test; fi
+ if ${HAVE_SDL2}; then ${MAKE} -C sdl2 test; fi
+
+update_sources:
+ ./update_sources
+
+.PHONY: \
+ all \
+ asan \
+ build \
+ clean \
+ cov \
+ debug \
+ demo \
+ demo_asan \
+ demo_cov \
+ demo_debug \
+ demo_gl \
+ demo_gl_asan \
+ demo_gl_cov \
+ demo_gl_debug \
+ distclean \
+ gdb_demo \
+ gdb_demo_gl \
+ install \
+ lldb_demo \
+ lldb_demo_gl \
+ test \
+ update_sources
+
+include config.mk
+include sources.mk
diff --git a/window/cairo/Makefile b/window/cairo/Makefile
new file mode 100644
index 0000000..36037c4
--- /dev/null
+++ b/window/cairo/Makefile
@@ -0,0 +1,126 @@
+## kc3
+## Copyright 2022-2024 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.
+
+build:
+ ${MAKE} ${LIB}
+ ${MAKE} -C demo build
+ if ${HAVE_COCOA}; then ${MAKE} -C quartz build; fi
+ if ${HAVE_WIN32}; then ${MAKE} -C win32 build; fi
+ if ${HAVE_XCB}; then ${MAKE} -C xcb build; fi
+
+all:
+ ${MAKE} build
+ if ${HAVE_GCOV}; then ${MAKE} cov; fi
+ ${MAKE} debug
+ if ${HAVE_ASAN}; then ${MAKE} asan; fi
+
+asan:
+ ${MAKE} ${LIB_ASAN}
+ ${MAKE} -C demo asan
+ if ${HAVE_COCOA}; then ${MAKE} -C quartz asan; fi
+ if ${HAVE_WIN32}; then ${MAKE} -C win32 asan; fi
+ if ${HAVE_XCB}; then ${MAKE} -C xcb asan; fi
+
+clean:
+ ${MAKE} -C demo clean
+ if ${HAVE_COCOA}; then ${MAKE} -C quartz clean; fi
+ if ${HAVE_WIN32}; then ${MAKE} -C win32 clean; fi
+ if ${HAVE_XCB}; then ${MAKE} -C xcb clean; fi
+
+clean_cov:
+ ${MAKE} -C demo clean_cov
+ if ${HAVE_COCOA}; then ${MAKE} -C quartz clean_cov; fi
+ if ${HAVE_WIN32}; then ${MAKE} -C win32 clean_cov; fi
+ if ${HAVE_XCB}; then ${MAKE} -C xcb clean_cov; fi
+
+cov:
+ ${MAKE} ${LIB_COV}
+ ${MAKE} -C demo cov
+ if ${HAVE_COCOA}; then ${MAKE} -C quartz cov; fi
+ if ${HAVE_WIN32}; then ${MAKE} -C win32 cov; fi
+ if ${HAVE_XCB}; then ${MAKE} -C xcb cov; fi
+
+debug:
+ ${MAKE} ${LIB_DEBUG}
+ ${MAKE} -C demo debug
+ if ${HAVE_COCOA}; then ${MAKE} -C quartz debug; else if ${HAVE_WIN32}; then ${MAKE} -C win32 debug; else if ${HAVE_XCB}; then ${MAKE} -C xcb debug; fi; fi; fi
+
+demo: build
+ if ${HAVE_COCOA}; then ${MAKE} -C quartz demo; else if ${HAVE_WIN32}; then ${MAKE} -C win32 demo; else if ${HAVE_XCB}; then ${MAKE} -C xcb demo; fi; fi; fi
+
+demo_asan: asan
+ if ${HAVE_COCOA}; then ${MAKE} -C quartz demo_asan; else if ${HAVE_WIN32}; then ${MAKE} -C win32 demo_asan; else if ${HAVE_XCB}; then ${MAKE} -C xcb demo_asan; fi; fi; fi
+
+demo_cov: cov
+ if ${HAVE_COCOA}; then ${MAKE} -C quartz demo_cov; else if ${HAVE_WIN32}; then ${MAKE} -C win32 demo_cov; else if ${HAVE_XCB}; then ${MAKE} -C xcb demo_cov; fi; fi; fi
+
+demo_debug: debug
+ if ${HAVE_COCOA}; then ${MAKE} -C quartz demo_debug; else if ${HAVE_WIN32}; then ${MAKE} -C win32 demo_debug; else if ${HAVE_XCB}; then ${MAKE} -C xcb demo_debug; fi; fi; fi
+
+distclean:
+ rm -rf ${DISTCLEANFILES}
+ ${MAKE} -C demo distclean
+ if ${HAVE_COCOA}; then ${MAKE} -C quartz distclean; fi
+ if ${HAVE_WIN32}; then ${MAKE} -C win32 distclean; fi
+ if ${HAVE_XCB}; then ${MAKE} -C xcb distclean; fi
+
+gcovr:
+ ${MAKE} -C demo gcovr
+ if ${HAVE_COCOA}; then ${MAKE} -C quartz gcovr; fi
+ if ${HAVE_WIN32}; then ${MAKE} -C win32 gcovr; fi
+ if ${HAVE_XCB}; then ${MAKE} -C xcb gcovr; fi
+
+gdb_demo: debug
+ if ${HAVE_COCOA}; then ${MAKE} -C quartz gdb_demo; else if ${HAVE_WIN32}; then ${MAKE} -C win32 gdb_demo; else if ${HAVE_XCB}; then ${MAKE} -C xcb gdb_demo; fi; fi; fi
+
+install:
+ ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0755 -d ${prefix}/include/libkc3/window/cairo
+ ${LIBTOOL} --tag=CC --mode=install ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0644 ${HEADERS} ${prefix}/include/libkc3/window/cairo
+ ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0755 -d ${prefix}/lib
+ ${LIBTOOL} --tag=CC --mode=install ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0644 ${LIB} ${prefix}/lib
+ ${LIBTOOL} --finish ${prefix}/lib
+ if ${HAVE_COCOA}; then ${MAKE} -C quartz install; fi
+ if ${HAVE_WIN32}; then ${MAKE} -C win32 install; fi
+ if ${HAVE_XCB}; then ${MAKE} -C xcb install; fi
+
+lldb_demo: debug
+ if ${HAVE_COCOA}; then ${MAKE} -C quartz lldb_demo; else if ${HAVE_WIN32}; then ${MAKE} -C win32 lldb_demo; else if ${HAVE_XCB}; then ${MAKE} -C xcb lldb_demo; fi; fi; fi
+
+test:
+ ${MAKE} -C demo test
+ if ${HAVE_COCOA}; then ${MAKE} -C quartz test; fi
+ if ${HAVE_WIN32}; then ${MAKE} -C win32 test; fi
+ if ${HAVE_XCB}; then ${MAKE} -C xcb test; fi
+
+update_sources:
+ ./update_sources
+
+.PHONY: \
+ all \
+ asan \
+ build \
+ clean \
+ cov \
+ debug \
+ demo \
+ demo_asan \
+ demo_cov \
+ demo_debug \
+ distclean \
+ gdb_demo \
+ install \
+ lldb_demo \
+ test \
+ update_sources
+
+include config.mk
+include sources.mk
diff --git a/window/cairo/cairo_font.c b/window/cairo/cairo_font.c
new file mode 100644
index 0000000..e527f38
--- /dev/null
+++ b/window/cairo/cairo_font.c
@@ -0,0 +1,84 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "cairo_font.h"
+
+static FT_Library *g_cairo_font_ft = NULL;
+
+static FT_Library * cairo_font_ft (void);
+
+void c3_window_cairo_font_clean (void)
+{
+ if (g_cairo_font_ft) {
+ FT_Done_FreeType(*g_cairo_font_ft);
+ free(g_cairo_font_ft);
+ }
+}
+
+void cairo_font_clean (s_cairo_font *font)
+{
+ assert(font);
+ cairo_font_face_destroy(font->cairo_font_face);
+ FT_Done_Face(font->ft_face);
+ str_clean(&font->path);
+ str_clean(&font->real_path);
+}
+
+static FT_Library * cairo_font_ft (void)
+{
+ if (! g_cairo_font_ft) {
+ g_cairo_font_ft = malloc(sizeof(FT_Library));
+ if (! g_cairo_font_ft) {
+ err_puts("cairo_font_ft: failed to allocate memory");
+ return NULL;
+ }
+ if (FT_Init_FreeType(g_cairo_font_ft)) {
+ err_puts("cairo_font_ft: error initializing FreeType");
+ free(g_cairo_font_ft);
+ g_cairo_font_ft = NULL;
+ return NULL;
+ }
+ }
+ return g_cairo_font_ft;
+}
+
+s_cairo_font * cairo_font_init (s_cairo_font *font, const char *path)
+{
+ FT_Library *ft;
+ assert(font);
+ assert(path);
+ if (! (ft = cairo_font_ft()))
+ return NULL;
+ str_init_copy_1(&font->path, path);
+ if (! file_search(&font->path, sym_1("r"), &font->real_path)) {
+ err_write_1("cairo_font_init: file not found: ");
+ err_puts(path);
+ str_clean(&font->path);
+ return NULL;
+ }
+ if (FT_New_Face(*ft, font->real_path.ptr.pchar, 0, &font->ft_face)) {
+ err_write_1("cairo_font_init: error loading font: ");
+ err_puts(font->real_path.ptr.pchar);
+ str_clean(&font->path);
+ str_clean(&font->real_path);
+ return NULL;
+ }
+ font->cairo_font_face = cairo_ft_font_face_create_for_ft_face
+ (font->ft_face, 0);
+ return font;
+}
+
+void cairo_set_font (cairo_t *cr, const s_cairo_font *font)
+{
+ cairo_set_font_face(cr, font->cairo_font_face);
+}
diff --git a/window/cairo/cairo_font.h b/window/cairo/cairo_font.h
new file mode 100644
index 0000000..68c7525
--- /dev/null
+++ b/window/cairo/cairo_font.h
@@ -0,0 +1,26 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_CAIRO_FONT_H
+#define LIBKC3_WINDOW_CAIRO_CAIRO_FONT_H
+
+#include "types.h"
+
+/* Stack-allocation compatible functions, call cairo_font_clean
+ after use. */
+void cairo_font_clean (s_cairo_font *font);
+s_cairo_font * cairo_font_init (s_cairo_font *font, const char *path);
+
+/* Observers */
+void cairo_set_font (cairo_t *cr, const s_cairo_font *font);
+
+#endif /* LIBKC3_WINDOW_CAIRO_CAIRO_FONT_H */
diff --git a/window/cairo/cairo_sprite.c b/window/cairo/cairo_sprite.c
new file mode 100644
index 0000000..477f6e8
--- /dev/null
+++ b/window/cairo/cairo_sprite.c
@@ -0,0 +1,137 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "cairo_sprite.h"
+
+void cairo_sprite_blit (const s_cairo_sprite *sprite, uw frame,
+ cairo_t *cr, uw x, uw y)
+{
+ assert(sprite);
+ assert(frame < sprite->frame_count);
+ assert(cr);
+ frame %= sprite->frame_count;
+ cairo_set_source_surface(cr, sprite->surface[frame], 0, 0);
+ cairo_rectangle(cr, x, y, sprite->w, sprite->h);
+ cairo_fill(cr);
+}
+
+void cairo_sprite_clean (s_cairo_sprite *sprite)
+{
+ void *data;
+ uw i;
+ assert(sprite);
+ i = 0;
+ while (i < sprite->frame_count) {
+ data = cairo_image_surface_get_data(sprite->surface[i]);
+ cairo_surface_destroy(sprite->surface[i]);
+ free(data);
+ i++;
+ }
+ free(sprite->surface);
+}
+
+s_cairo_sprite * cairo_sprite_init (s_cairo_sprite *sprite,
+ const char *path,
+ uw dim_x, uw dim_y,
+ uw frame_count)
+{
+ assert(sprite);
+ assert(dim_x);
+ assert(dim_y);
+ u8 *dest_data;
+ uw dest_stride;
+ uw i;
+ cairo_surface_t *src;
+ u8 *src_data;
+ uw src_stride;
+ uw u;
+ uw v;
+ uw x;
+ uw y;
+ assert(sprite);
+ assert(path);
+ assert(dim_x);
+ assert(dim_y);
+ str_init_copy_1(&sprite->path, path);
+ if (! file_search(&sprite->path, sym_1("r"), &sprite->real_path)) {
+ err_write_1("cairo_sprite_init: file not found: ");
+ err_puts(path);
+ str_clean(&sprite->path);
+ return NULL;
+ }
+ src =
+ cairo_image_surface_create_from_png(sprite->real_path.ptr.pchar);
+ if (! src) {
+ err_write_1("cairo_sprite_init: error loading image: ");
+ err_puts(sprite->real_path.ptr.pchar);
+ str_clean(&sprite->path);
+ str_clean(&sprite->real_path);
+ return NULL;
+ }
+ sprite->total_w = cairo_image_surface_get_width(src);
+ sprite->total_h = cairo_image_surface_get_height(src);
+ sprite->dim_x = dim_x;
+ sprite->dim_y = dim_y;
+ sprite->w = sprite->total_w / dim_x;
+ sprite->h = sprite->total_h / dim_y;
+ sprite->frame_count = frame_count ? frame_count : (dim_x * dim_y);
+ sprite->surface = calloc(frame_count, sizeof(cairo_surface_t *));
+ if (! sprite->surface) {
+ err_puts("cairo_sprite_init: sprite->surface:"
+ " failed to allocate memory");
+ cairo_surface_destroy(src);
+ str_clean(&sprite->path);
+ str_clean(&sprite->real_path);
+ return NULL;
+ }
+ i = 0;
+ y = 0;
+ while (i < sprite->frame_count && y < dim_y) {
+ x = 0;
+ while (i < sprite->frame_count && x < dim_x) {
+ src_data = cairo_image_surface_get_data(src);
+ src_stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32,
+ sprite->total_w);
+ dest_stride =
+ cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, sprite->w);
+ dest_data = malloc(sprite->h * dest_stride);
+ sprite->surface[i] =
+ cairo_image_surface_create_for_data(dest_data,
+ CAIRO_FORMAT_ARGB32,
+ sprite->w, sprite->h,
+ dest_stride);
+ v = 0;
+ while (v < sprite->h) {
+ u = 0;
+ while (u < sprite->w) {
+ u8 *dest_pixel = dest_data + v * dest_stride +
+ u * 4;
+ u8 *src_pixel = src_data +
+ (y * sprite->h + v) * src_stride +
+ (x * sprite->w + u) * 4;
+ dest_pixel[0] = src_pixel[0];
+ dest_pixel[1] = src_pixel[1];
+ dest_pixel[2] = src_pixel[2];
+ dest_pixel[3] = src_pixel[3];
+ u++;
+ }
+ v++;
+ }
+ i++;
+ x++;
+ }
+ y++;
+ }
+ cairo_surface_destroy(src);
+ return sprite;
+}
diff --git a/window/cairo/cairo_sprite.h b/window/cairo/cairo_sprite.h
new file mode 100644
index 0000000..86c2334
--- /dev/null
+++ b/window/cairo/cairo_sprite.h
@@ -0,0 +1,30 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 CAIRO_SPRITE_H
+#define CAIRO_SPRITE_H
+
+#include "types.h"
+#include <cairo.h>
+
+/* stack allocation compatible functions */
+void cairo_sprite_clean (s_cairo_sprite *sprite);
+s_cairo_sprite * cairo_sprite_init (s_cairo_sprite *sprite,
+ const char *path,
+ uw dim_x, uw dim_y,
+ uw frame_count);
+
+/* operations */
+void cairo_sprite_blit (const s_cairo_sprite *sprite, uw frame,
+ cairo_t *cr, uw x, uw y);
+
+#endif /* CAIRO_SPRITE_H */
diff --git a/window/cairo/cairo_text.c b/window/cairo/cairo_text.c
new file mode 100644
index 0000000..d143bb8
--- /dev/null
+++ b/window/cairo/cairo_text.c
@@ -0,0 +1,39 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "cairo_text.h"
+
+void cairo_text_outline (cairo_t *cr, double x, double y,
+ const char *p)
+{
+ cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
+ cairo_move_to(cr, x - 1.0, y - 1.0);
+ cairo_show_text(cr, p);
+ cairo_move_to(cr, x - 1.0, y);
+ cairo_show_text(cr, p);
+ cairo_move_to(cr, x - 1.0, y + 1.0);
+ cairo_show_text(cr, p);
+ cairo_move_to(cr, x, y - 1.0);
+ cairo_show_text(cr, p);
+ cairo_move_to(cr, x, y + 1.0);
+ cairo_show_text(cr, p);
+ cairo_move_to(cr, x + 1.0, y - 1.0);
+ cairo_show_text(cr, p);
+ cairo_move_to(cr, x + 1.0, y);
+ cairo_show_text(cr, p);
+ cairo_move_to(cr, x + 1.0, y + 1.0);
+ cairo_show_text(cr, p);
+ cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
+ cairo_move_to(cr, x, y);
+ cairo_show_text(cr, p);
+}
diff --git a/window/cairo/cairo_text.h b/window/cairo/cairo_text.h
new file mode 100644
index 0000000..21533c5
--- /dev/null
+++ b/window/cairo/cairo_text.h
@@ -0,0 +1,27 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_CAIRO_TEXT_H
+#define LIBKC3_WINDOW_CAIRO_CAIRO_TEXT_H
+
+#include "types.h"
+
+/* Stack-allocation compatible functions, call cairo_font_clean
+ after use. */
+void cairo_font_clean (s_cairo_font *font);
+s_cairo_font * cairo_font_init (s_cairo_font *font, const char *path);
+
+/* Observers */
+void cairo_text_outline (cairo_t *cr, double x, double y,
+ const char *p);
+
+#endif /* LIBKC3_WINDOW_CAIRO_CAIRO_TEXT_H */
diff --git a/window/cairo/configure b/window/cairo/configure
new file mode 100755
index 0000000..86a86f3
--- /dev/null
+++ b/window/cairo/configure
@@ -0,0 +1,148 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+set -e
+
+echo "$PWD/configure"
+
+export SRC_TOP="$(dirname "$PWD")"
+
+CONFIG_H_PREFIX=LIBKC3_WINDOW_CAIRO_
+
+. ../../config.subr
+
+LIB=libkc3_window_cairo.la
+LIB_ASAN=libkc3_window_cairo_asan.la
+LIB_COV=libkc3_window_cairo_cov.la
+LIB_DEBUG=libkc3_window_cairo_debug.la
+
+echo "LIB = $LIB" >> ${CONFIG_MK}
+echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
+echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
+echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
+
+. ./sources.sh
+
+OBJECTS="$(c2ext .main.lo "$SOURCES")"
+echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
+OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
+OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
+OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
+
+# Common config for all targets
+CPPFLAGS="-I../.. $CPPFLAGS"
+OBJCFLAGS="$CFLAGS -W -Wall -Werror"
+CFLAGS="$CFLAGS -W -Wall -Werror -std=c11 -pedantic -pipe"
+LDFLAGS="--shared ${LDFLAGS}"
+LIBS="$LIBS -rpath ${PREFIX}/lib"
+config_asan
+config_gnu
+config_i386
+pkg_config libbsd-overlay
+pkg_config libffi
+pkg_config libmd
+pkg_config cairo
+pkg_config cairo-ft
+pkg_config freetype2
+pkg_config xkbcommon
+config_lib_have COCOA -framework Cocoa
+config_define PREFIX "\"${PREFIX}\""
+
+# Address Sanitizer config
+CPPFLAGS_ASAN="$CPPFLAGS"
+CFLAGS_ASAN="$CFLAGS -O1 -fsanitize=address -fno-omit-frame-pointer -g"
+LDFLAGS_ASAN="$LDFLAGS"
+LIBS_LOCAL_ASAN="../libkc3_window_asan.la"
+LIBS_ASAN="$LIBS_LOCAL_ASAN $LIBS"
+
+# Coverage config
+CPPFLAGS_COV="$CPPFLAGS"
+CFLAGS_COV="$CFLAGS -ftest-coverage -fprofile-arcs -fprofile-generate"
+LDFLAGS_COV="$LDFLAGS --coverage"
+LIBS_LOCAL_COV="../libkc3_window_cov.la"
+LIBS_COV="$LIBS_LOCAL_COV $LIBS"
+
+# Debug config
+CPPFLAGS_DEBUG="$CPPFLAGS"
+CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
+LDFLAGS_DEBUG="$LDFLAGS"
+LIBS_LOCAL_DEBUG="../libkc3_window_debug.la"
+LIBS_DEBUG="$LIBS_LOCAL_DEBUG $LIBS"
+
+# Main config
+DEFAULT_CFLAGS="-O2 -fPIC"
+if [ "x$ENV_CFLAGS" = "x" ]; then
+ CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
+fi
+CFLAGS="$CFLAGS -DNDEBUG"
+LIBS_LOCAL="../libkc3_window.la"
+LIBS="$LIBS_LOCAL $LIBS"
+
+echo "LIB = $LIB" >> ${CONFIG_MK}
+echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
+echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
+echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
+echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
+echo "LIBS = $LIBS" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
+echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
+echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
+echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
+echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
+echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
+
+update_build
+update_build_lib
+
+build_lo
+build_lib
+
+if pkg-config cairo-xcb; then
+ HAVE_XCB=true
+else
+ HAVE_XCB=false
+fi
+echo "HAVE_XCB = $HAVE_XCB" >> ${CONFIG_MK}
+
+if pkg-config cairo-win32; then
+ HAVE_WIN32=true
+else
+ HAVE_WIN32=false
+fi
+echo "HAVE_WIN32 = $HAVE_WIN32" >> ${CONFIG_MK}
+
+update_config_mk
+env_reset
+
+config_subdirs demo
+
+if ${HAVE_COCOA}; then
+ config_subdirs quartz
+fi
+
+if ${HAVE_WIN32}; then
+ config_subdirs win32
+fi
+
+if ${HAVE_XCB}; then
+ config_subdirs xcb
+fi
diff --git a/window/cairo/demo/Makefile b/window/cairo/demo/Makefile
new file mode 100644
index 0000000..bf4c7f2
--- /dev/null
+++ b/window/cairo/demo/Makefile
@@ -0,0 +1,65 @@
+## kc3
+## Copyright 2022-2024 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.
+
+CLEANFILES = *.a *.gcno *.la .libs *.lo *.o
+
+CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
+
+CLEANFILES += ${CLEANFILES_COV}
+
+DISTCLEANFILES = ${CLEANFILES} config.h config.mk
+
+build:
+ ${MAKE} ${LIB}
+
+all:
+ ${MAKE} build
+ if ${HAVE_GCOV}; then ${MAKE} cov; fi
+ ${MAKE} debug
+ if ${HAVE_ASAN}; then ${MAKE} asan; fi
+
+asan:
+ ${MAKE} ${LIB_ASAN}
+
+clean:
+ rm -rf ${CLEANFILES}
+
+clean_cov:
+ rm -rf ${CLEANFILES_COV}
+
+cov:
+ ${MAKE} ${LIB_COV}
+
+debug:
+ ${MAKE} ${LIB_DEBUG}
+
+distclean:
+ rm -rf ${DISTCLEANFILES}
+
+gcovr:
+ gcovr --gcov-executable ${GCOV} --html-details demo.html
+
+update_sources:
+ ./update_sources
+
+.PHONY: \
+ all \
+ asan \
+ build \
+ clean \
+ cov \
+ debug \
+ distclean \
+ update_sources
+
+include config.mk
+include sources.mk
diff --git a/window/cairo/demo/bg_rect.c b/window/cairo/demo/bg_rect.c
new file mode 100644
index 0000000..f32035a
--- /dev/null
+++ b/window/cairo/demo/bg_rect.c
@@ -0,0 +1,64 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "../types.h"
+#include "bg_rect.h"
+
+#define BG_RECT_COLOR_MAX 8
+
+bool bg_rect_load (s_sequence *seq)
+{
+ (void) seq;
+ return true;
+}
+
+bool bg_rect_render (s_sequence *seq)
+{
+ const s_rgb color[BG_RECT_COLOR_MAX] = {
+ {0, 0, 0},
+ {1, 0, 0},
+ {1, 1, 0},
+ {0, 1, 0},
+ {0, 1, 1},
+ {0, 0, 1},
+ {1, 0, 1},
+ {1, 1, 1}
+ };
+ u8 c1;
+ u8 c2;
+ cairo_t *cr;
+ double p;
+ double q;
+ s_rgb rgb;
+ s_window_cairo *window;
+ window = seq->window;
+ cr = window->cr;
+ c1 = (u8) trunc(seq->t) % BG_RECT_COLOR_MAX;
+ c2 = (u8) trunc(seq->t + 1.0) % BG_RECT_COLOR_MAX;
+ p = fmod(seq->t, 1.0);
+ q = 1.0 - p;
+ rgb.r = color[c1].r * q + color[c2].r * p;
+ rgb.g = color[c1].g * q + color[c2].g * p;
+ rgb.b = color[c1].b * q + color[c2].b * p;
+ cairo_set_source_rgb(cr, rgb.r, rgb.g, rgb.b);
+ cairo_rectangle(cr, 0, 0, window->w, window->h);
+ cairo_fill(cr);
+ return true;
+}
+
+bool bg_rect_unload (s_sequence *seq)
+{
+ (void) seq;
+ return true;
+}
diff --git a/window/cairo/demo/bg_rect.h b/window/cairo/demo/bg_rect.h
new file mode 100644
index 0000000..144f39d
--- /dev/null
+++ b/window/cairo/demo/bg_rect.h
@@ -0,0 +1,22 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 BG_RECT_H
+#define BG_RECT_H
+
+#include "../types.h"
+
+bool bg_rect_load (s_sequence *seq);
+bool bg_rect_render (s_sequence *seq);
+bool bg_rect_unload (s_sequence *seq);
+
+#endif /* BG_RECT_H */
diff --git a/window/cairo/demo/configure b/window/cairo/demo/configure
new file mode 100755
index 0000000..682e3dd
--- /dev/null
+++ b/window/cairo/demo/configure
@@ -0,0 +1,124 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+set -e
+
+echo "$PWD/configure"
+
+export SRC_TOP="$(dirname "$PWD")"
+
+CONFIG_H_PREFIX=LIBKC3_WINDOW_CAIRO_DEMO_
+
+. ../../../config.subr
+
+LIB=libkc3_window_cairo_demo.la
+LIB_ASAN=libkc3_window_cairo_demo_asan.la
+LIB_COV=libkc3_window_cairo_demo_cov.la
+LIB_DEBUG=libkc3_window_cairo_demo_debug.la
+
+echo "LIB = $LIB" >> ${CONFIG_MK}
+echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
+echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
+echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
+
+. ./sources.sh
+
+OBJECTS="$(c2ext .main.lo "$SOURCES")"
+echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
+OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
+OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
+OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
+
+# Common config for all targets
+CPPFLAGS="-I../../.. $CPPFLAGS"
+CFLAGS="$CFLAGS -W -Wall -Werror -std=c11 -pedantic -pipe"
+LDFLAGS="--shared ${LDFLAGS}"
+LIBS="$LIBS -rpath ${PREFIX}/lib"
+config_asan
+config_gnu
+config_i386
+pkg_config libbsd-overlay
+pkg_config libffi
+pkg_config libmd
+pkg_config cairo
+pkg_config xkbcommon
+config_define PREFIX "\"${PREFIX}\""
+
+# Address Sanitizer config
+CPPFLAGS_ASAN="$CPPFLAGS"
+CFLAGS_ASAN="$CFLAGS -DDEBUG -O1 -g"
+CFLAGS_ASAN="$CFLAGS_ASAN -fsanitize=address -fno-omit-frame-pointer"
+LDFLAGS_ASAN="$LDFLAGS"
+LIBS_LOCAL_ASAN="../libkc3_window_cairo_asan.la"
+LIBS_LOCAL_ASAN="$LIBS_LOCAL_ASAN ../../libkc3_window_asan.la"
+LIBS_LOCAL_ASAN="$LIBS_LOCAL_ASAN ../../../libkc3/libkc3_asan.la"
+LIBS_ASAN="$LIBS_LOCAL_ASAN $LIBS"
+
+# Coverage config
+CPPFLAGS_COV="$CPPFLAGS"
+CFLAGS_COV="$CFLAGS -DDEBUG --coverage"
+LDFLAGS_COV="$LDFLAGS"
+LIBS_LOCAL_COV="../libkc3_window_cairo_cov.la"
+LIBS_LOCAL_COV="$LIBS_LOCAL_COV ../../libkc3_window_cov.la"
+LIBS_LOCAL_COV="$LIBS_LOCAL_COV ../../../libkc3/libkc3_cov.la"
+LIBS_COV="$LIBS_LOCAL_COV $LIBS"
+
+# Debug config
+CPPFLAGS_DEBUG="$CPPFLAGS"
+CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
+LDFLAGS_DEBUG="$LDFLAGS"
+LIBS_LOCAL_DEBUG="../libkc3_window_cairo_debug.la"
+LIBS_LOCAL_DEBUG="$LIBS_LOCAL_DEBUG ../../libkc3_window_debug.la"
+LIBS_LOCAL_DEBUG="$LIBS_LOCAL_DEBUG ../../../libkc3/libkc3_debug.la"
+LIBS_DEBUG="$LIBS_LOCAL_DEBUG $LIBS"
+
+# Main config
+DEFAULT_CFLAGS="-O2 -pipe"
+if [ "x$ENV_CFLAGS" = "x" ]; then
+ CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
+fi
+CFLAGS="$CFLAGS -DNDEBUG"
+LIBS_LOCAL="../libkc3_window_cairo.la"
+LIBS_LOCAL="$LIBS_LOCAL ../../libkc3_window.la"
+LIBS_LOCAL="$LIBS_LOCAL ../../../libkc3/libkc3.la"
+LIBS="$LIBS_LOCAL $LIBS"
+
+echo "LIB = $LIB" >> ${CONFIG_MK}
+echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
+echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
+echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
+echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
+echo "LIBS = $LIBS" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
+echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
+echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
+echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
+echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
+echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
+
+update_build
+update_build_lib
+
+build_lo
+build_lib
+
+update_config_mk
diff --git a/window/cairo/demo/flies.c b/window/cairo/demo/flies.c
new file mode 100644
index 0000000..455d560
--- /dev/null
+++ b/window/cairo/demo/flies.c
@@ -0,0 +1,319 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "../cairo_font.h"
+#include "../cairo_sprite.h"
+#include "../window_cairo.h"
+#include "window_cairo_demo.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_cairo_sprite g_sprite_dead_fly = {0};
+s_cairo_sprite g_sprite_fly = {0};
+static const f64 g_xy_ratio = 0.6;
+
+static void fly_init (s_map *map)
+{
+ uw address[2] = { BOARD_SIZE / 2,
+ 0 };
+ s_array *board;
+ uw *in;
+ f64 *t;
+ board = &map->value[0].data.array;
+ in = &map->value[1].data.uw;
+ t = &map->value[3].data.f64;
+ array_data_set(board, address, &g_board_item_fly);
+ *t = 0.0;
+ (*in)++;
+}
+
+bool flies_load (s_sequence *seq)
+{
+ uw address[2];
+ s_array *board;
+ uw i;
+ uw j;
+ s_map *map;
+ tag_map(&seq->tag, 4);
+ map = &seq->tag.data.map;
+ tag_init_sym( map->key + 0, sym_1("board"));
+ tag_init_array(map->value + 0, sym_1("U8[]"),
+ 2, (uw[]) {BOARD_SIZE, BOARD_SIZE});
+ tag_init_sym(map->key + 1, sym_1("in"));
+ tag_init_uw( map->value + 1, 0);
+ tag_init_sym(map->key + 2, sym_1("out"));
+ tag_init_uw( map->value + 2, 0);
+ tag_init_sym(map->key + 3, sym_1("t"));
+ tag_init_uw( map->value + 3, 0);
+ board = &map->value[0].data.array;
+ array_allocate(board);
+ 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)
+{
+ char 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;
+ cairo_t *cr;
+ 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;
+ cairo_text_extents_t te;
+ f64 x;
+ f64 y;
+ s_window_cairo *window;
+ window = seq->window;
+ cr = window->cr;
+ cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
+ cairo_rectangle(cr, 0, 0, window->w, window->h);
+ cairo_fill(cr);
+ /* io_inspect(&seq->tag); */
+ if (seq->tag.type == TAG_MAP) {
+ map = &seq->tag.data.map;
+ if (map->count == 4 &&
+ map->value[0].type == TAG_ARRAY &&
+ map->value[1].type == TAG_UW &&
+ map->value[2].type == TAG_UW &&
+ map->value[3].type == TAG_UW) {
+ board = &map->value[0].data.array;
+ fly_in = &map->value[1].data.uw;
+ fly_out = &map->value[2].data.uw;
+ fly_time = &map->value[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_sprite_fly.w;
+ dead_fly_scale = 2.0 * board_item_w / g_sprite_dead_fly.w;
+ cairo_set_source_rgb(cr, 0.6, 0.7, 0.9);
+ cairo_rectangle(cr, board_x, 0, board_w, board_h);
+ cairo_fill(cr);
+ cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
+ cairo_set_font_size(cr, board_item_h);
+ cairo_set_font(cr, &g_font_courier_new);
+ buf_init(&buf, false, sizeof(a), a);
+ buf_write_1(&buf, "In ");
+ buf_inspect_uw(&buf, fly_in);
+ buf_write_u8(&buf, 0);
+ cairo_text_extents(cr, buf.ptr.pchar, &te);
+ y = board_h + board_item_h + te.height + te.y_bearing;
+ x = board_x;
+ cairo_move_to(cr, x, y);
+ cairo_show_text(cr, buf.ptr.pchar);
+ 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_x + board_item_w * (BOARD_SIZE / 2 + 1);
+ cairo_move_to(cr, x, y);
+ cairo_show_text(cr, buf.ptr.pchar);
+ address[1] = 0;
+ while (address[1] < BOARD_SIZE) {
+ y = board_item_h * address[1];
+ address[0] = 0;
+ while (address[0] < BOARD_SIZE) {
+ x = board_x + board_item_w * address[0];
+ cairo_translate(cr, x, y);
+ board_item = (u8 *) array_data(board, address);
+ assert(board_item);
+ switch (*board_item) {
+ case BOARD_ITEM_SPACE:
+ break;
+ case BOARD_ITEM_BLOCK:
+ cairo_set_source_rgb(cr, 0.0, 0.0, 1.0);
+ cairo_rectangle(cr, 0, 0, board_item_w + 1.0,
+ board_item_h + 1.0);
+ cairo_fill(cr);
+ break;
+ case BOARD_ITEM_FLY:
+ cairo_translate(cr, -board_item_w / 2.0,
+ -board_item_h / 2.0);
+ cairo_scale(cr, fly_scale, fly_scale);
+ cairo_sprite_blit(&g_sprite_fly, 0,
+ cr, 0, 0);
+ 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 = arc4random();
+ random_bits = 32;
+ }
+ 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:
+ cairo_translate(cr, -board_item_w / 2.0,
+ -board_item_h / 2.0);
+ cairo_scale(cr, dead_fly_scale, dead_fly_scale);
+ cairo_sprite_blit(&g_sprite_dead_fly, 0,
+ cr, 0, 0);
+ break;
+ }
+ cairo_identity_matrix(cr);
+ address[0]++;
+ }
+ address[1]++;
+ }
+ }
+ }
+ return true;
+}
+
+bool flies_unload (s_sequence *seq)
+{
+ (void) seq;
+ return true;
+}
diff --git a/window/cairo/demo/flies.h b/window/cairo/demo/flies.h
new file mode 100644
index 0000000..410e147
--- /dev/null
+++ b/window/cairo/demo/flies.h
@@ -0,0 +1,25 @@
+/* kc3
+ * Copyright 2022,2023,2024 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"
+
+extern s_cairo_sprite g_sprite_dead_fly;
+extern s_cairo_sprite g_sprite_fly;
+
+bool flies_load (s_sequence *seq);
+bool flies_render (s_sequence *seq);
+bool flies_unload (s_sequence *seq);
+
+#endif /* FLIES_H */
diff --git a/window/cairo/demo/lightspeed.c b/window/cairo/demo/lightspeed.c
new file mode 100644
index 0000000..6eeaffe
--- /dev/null
+++ b/window/cairo/demo/lightspeed.c
@@ -0,0 +1,95 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "lightspeed.h"
+
+static void star_init (s_tag *star)
+{
+ f64 x;
+ f64 y;
+ f64_random(&x);
+ f64_random(&y);
+ tag_map(star, 3);
+ tag_init_sym(star->data.map.key, sym_1("speed"));
+ tag_init_f64(star->data.map.value, 0.0);
+ tag_init_sym(star->data.map.key + 1, sym_1("x"));
+ tag_init_f64(star->data.map.value + 1, 2.0 * x - 1.0);
+ tag_init_sym(star->data.map.key + 2, sym_1("y"));
+ tag_init_f64(star->data.map.value + 2, 2.0 * y - 1.0);
+}
+
+static void star_render (s_tag *star, s_window_cairo *window,
+ cairo_t *cr, s_sequence *seq)
+{
+ f64 q;
+ f64 *speed;
+ f64 *x;
+ f64 *y;
+ (void) window;
+ speed = &star->data.map.value[0].data.f64;
+ x = &star->data.map.value[1].data.f64;
+ y = &star->data.map.value[2].data.f64;
+ cairo_set_line_width(cr, 0.004);
+ cairo_set_source_rgb(cr, 1, 1, 1);
+ cairo_move_to(cr, *x, *y);
+ q = (1 + *speed / 20);
+ cairo_line_to(cr, *x * q, *y * q);
+ cairo_stroke(cr);
+ 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)
+{
+ uw i;
+ 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)
+{
+ cairo_t *cr;
+ uw i;
+ cairo_matrix_t matrix;
+ s_window_cairo *window;
+ window = seq->window;
+ cr = window->cr;
+ cairo_get_matrix(cr, &matrix);
+ cairo_scale(cr, window->w / 2.0, window->h / 2.0);
+ cairo_translate(cr, 1.0, 1.0);
+ cairo_set_source_rgb(cr, 0, 0, 0);
+ cairo_rectangle(cr, -1, -1, 2, 2);
+ cairo_fill(cr);
+ i = 0;
+ while (i < LIGHTSPEED_STARS) {
+ star_render(seq->tag.data.tuple.tag + i, window, cr, seq);
+ i++;
+ }
+ cairo_set_matrix(cr, &matrix);
+ return true;
+}
+
+bool lightspeed_unload (s_sequence *seq)
+{
+ (void) seq;
+ return true;
+}
diff --git a/window/cairo/demo/lightspeed.h b/window/cairo/demo/lightspeed.h
new file mode 100644
index 0000000..efc1992
--- /dev/null
+++ b/window/cairo/demo/lightspeed.h
@@ -0,0 +1,24 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 1000
+
+bool lightspeed_load (s_sequence *seq);
+bool lightspeed_render (s_sequence *seq);
+bool lightspeed_unload (s_sequence *seq);
+
+#endif /* LIGHTSPEED_H */
diff --git a/window/cairo/demo/mandelbrot_f128.c b/window/cairo/demo/mandelbrot_f128.c
new file mode 100644
index 0000000..21fd69d
--- /dev/null
+++ b/window/cairo/demo/mandelbrot_f128.c
@@ -0,0 +1,275 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "../cairo_text.h"
+#include "mandelbrot_f128.h"
+
+static cairo_surface_t *g_mandelbrot_f128_surface = NULL;
+
+static bool mandelbrot_f128_resize (s_sequence *seq);
+static bool mandelbrot_f128_update (s_sequence *seq);
+
+bool mandelbrot_f128_button (s_sequence *seq, u8 button, sw x, sw y)
+{
+ s_map *map;
+ f128 *next_x;
+ f128 *next_y;
+ f128 *next_z;
+ s_window_cairo *win;
+ assert(seq);
+ win = seq->window;
+ assert(win);
+ 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;
+ if (button == 1) {
+ *next_x = *next_x + *next_z * (x - (f128) win->w / 2);
+ *next_y = *next_y + *next_z * (y - (f128) win->h / 2);
+ }
+ else if (button == 5) {
+ *next_z = *next_z * exp2l(0.5);
+ }
+ else if (button == 4) {
+ *next_z = *next_z * exp2l(-0.5);
+ }
+ return true;
+}
+
+bool mandelbrot_f128_load (s_sequence *seq)
+{
+ s_map *map;
+ assert(seq);
+ 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("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.0);
+ return true;
+}
+
+bool mandelbrot_f128_render (s_sequence *seq)
+{
+ cairo_t *cr;
+ uw *h;
+ s_map *map;
+ f128 next_x;
+ f128 next_y;
+ f128 next_z;
+ uw *w;
+ s_window_cairo *win;
+ f128 *x;
+ f128 *y;
+ f128 *z;
+ assert(seq);
+ win = seq->window;
+ assert(win);
+ cr = win->cr;
+ 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("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[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 (! g_mandelbrot_f128_surface ||
+ *w != win->w || *h != win->h)
+ 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;
+ }
+ cairo_identity_matrix(cr);
+ cairo_set_source_surface(cr, g_mandelbrot_f128_surface, 0, 0);
+ cairo_rectangle(cr, 0, 0, win->w, win->h);
+ cairo_fill(cr);
+ char a[128];
+ s_buf buf;
+ buf_init(&buf, false, sizeof(a), a);
+ buf_write_1(&buf, "x: ");
+ buf_inspect_f128(&buf, &next_x);
+ buf_write_u8(&buf, 0);
+ cairo_text_outline(cr, 20, win->h - 100, a);
+ buf_init(&buf, false, sizeof(a), a);
+ buf_write_1(&buf, "y: ");
+ buf_inspect_f128(&buf, &next_y);
+ buf_write_u8(&buf, 0);
+ cairo_text_outline(cr, 20, win->h - 80, a);
+ buf_init(&buf, false, sizeof(a), a);
+ buf_write_1(&buf, "z: ");
+ buf_inspect_f128(&buf, &next_z);
+ buf_write_u8(&buf, 0);
+ cairo_text_outline(cr, 20, win->h - 60, a);
+ return true;
+}
+
+static bool mandelbrot_f128_resize (s_sequence *seq)
+{
+ s_window_cairo *win;
+ assert(seq);
+ win = seq->window;
+ assert(win);
+ cairo_surface_destroy(g_mandelbrot_f128_surface);
+ g_mandelbrot_f128_surface =
+ cairo_image_surface_create(CAIRO_FORMAT_RGB24,
+ win->w, win->h);
+ return true;
+}
+
+bool mandelbrot_f128_unload (s_sequence *seq)
+{
+ (void) seq;
+ cairo_surface_destroy(g_mandelbrot_f128_surface);
+ g_mandelbrot_f128_surface = NULL;
+ return true;
+}
+
+static bool mandelbrot_f128_update (s_sequence *seq)
+{
+ f128 _2z_xz_y;
+ f128 c_x;
+ f128 c_y;
+ u8 *data;
+ uw i;
+ uw j;
+ u8 k;
+ u8 level;
+ s_map *map;
+ f128 next_x;
+ f128 next_y;
+ f128 next_z;
+ u8 *pix;
+ uw stride;
+ s_window_cairo *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;
+ cairo_surface_flush(g_mandelbrot_f128_surface);
+ data = cairo_image_surface_get_data(g_mandelbrot_f128_surface);
+ assert(data);
+ stride = cairo_image_surface_get_stride(g_mandelbrot_f128_surface);
+ i = 0;
+ while (i < win->h) {
+ c_y = next_y + next_z * ((f128) i - win->h / 2);
+ pix = data + i * stride;
+ j = 0;
+ while (j < win->w) {
+ c_x = next_x + next_z * ((f128) 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 = 255 - k;
+ /*if (k)
+ printf("x %lu, y %lu, k %d, level %d", j, i, k, level);*/
+ pix[0] = level;
+ pix[1] = level;
+ pix[2] = level;
+ pix += 4;
+ j++;
+ }
+ i++;
+ }
+ cairo_surface_mark_dirty(g_mandelbrot_f128_surface);
+ return true;
+}
diff --git a/window/cairo/demo/mandelbrot_f128.h b/window/cairo/demo/mandelbrot_f128.h
new file mode 100644
index 0000000..3a95d69
--- /dev/null
+++ b/window/cairo/demo/mandelbrot_f128.h
@@ -0,0 +1,23 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 MANDELBROT_F128_H
+#define MANDELBROT_F128_H
+
+#include "../types.h"
+
+bool mandelbrot_f128_button (s_sequence *seq, u8 button, sw x, sw y);
+bool mandelbrot_f128_load (s_sequence *seq);
+bool mandelbrot_f128_render (s_sequence *seq);
+bool mandelbrot_f128_unload (s_sequence *seq);
+
+#endif /* MANDELBROT_F128_H */
diff --git a/window/cairo/demo/sources.mk b/window/cairo/demo/sources.mk
new file mode 100644
index 0000000..3d8cbec
--- /dev/null
+++ b/window/cairo/demo/sources.mk
@@ -0,0 +1,17 @@
+# sources.mk generated by update_sources
+HEADERS = \
+ "bg_rect.h" \
+ "flies.h" \
+ "lightspeed.h" \
+ "mandelbrot_f128.h" \
+ "toasters.h" \
+ "window_cairo_demo.h" \
+
+SOURCES = \
+ "bg_rect.c" \
+ "flies.c" \
+ "lightspeed.c" \
+ "mandelbrot_f128.c" \
+ "toasters.c" \
+ "window_cairo_demo.c" \
+
diff --git a/window/cairo/demo/sources.sh b/window/cairo/demo/sources.sh
new file mode 100644
index 0000000..6cd2723
--- /dev/null
+++ b/window/cairo/demo/sources.sh
@@ -0,0 +1,3 @@
+# sources.sh generated by update_sources
+HEADERS='bg_rect.h flies.h lightspeed.h mandelbrot_f128.h toasters.h window_cairo_demo.h '
+SOURCES='bg_rect.c flies.c lightspeed.c mandelbrot_f128.c toasters.c window_cairo_demo.c '
diff --git a/window/cairo/demo/toasters.c b/window/cairo/demo/toasters.c
new file mode 100644
index 0000000..09efc9f
--- /dev/null
+++ b/window/cairo/demo/toasters.c
@@ -0,0 +1,242 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "../cairo_sprite.h"
+#include "toasters.h"
+
+static const f64 g_speed_x = 80.0;
+static const f64 g_speed_y = -40.0;
+s_cairo_sprite g_sprite_toast = {0};
+s_cairo_sprite g_sprite_toaster = {0};
+
+static bool toasters_render_toasters (s_list **toasters,
+ s_window_cairo *window,
+ cairo_t *cr,
+ s_sequence *seq);
+static bool toasters_render_toasts (s_list **toasts,
+ s_window_cairo *window,
+ cairo_t *cr,
+ s_sequence *seq);
+
+static s_tag * toast_init (s_tag *toast, f64 x, f64 y)
+{
+ tag_init_map(toast, 2);
+ tag_init_sym(toast->data.map.key + 0, sym_1("x"));
+ tag_init_f64(toast->data.map.value + 0, x);
+ tag_init_sym(toast->data.map.key + 1, sym_1("y"));
+ tag_init_f64(toast->data.map.value + 1, y);
+ return toast;
+}
+
+static void toast_render (s_tag *toast, s_window_cairo *window,
+ cairo_t *cr, s_sequence *seq)
+{
+ cairo_matrix_t matrix;
+ f64 *x;
+ f64 *y;
+ if (toast->type == TAG_MAP) {
+ x = &toast->data.map.value[0].data.f64;
+ y = &toast->data.map.value[1].data.f64;
+ *x -= seq->dt * g_speed_x;
+ *y -= seq->dt * g_speed_y;
+ if (*x < -100 || *y > window->h) {
+ tag_clean(toast);
+ toast->type = TAG_VOID;
+ return;
+ }
+ cairo_get_matrix(cr, &matrix);
+ cairo_translate(cr, *x, *y);
+ cairo_sprite_blit(&g_sprite_toast, 0, cr, 0, 0);
+ cairo_set_matrix(cr, &matrix);
+ }
+}
+
+static s_tag * toaster_init (s_tag *toaster, f64 y)
+{
+ tag_init_map(toaster, 2);
+ tag_init_sym(toaster->data.map.key + 0, sym_1("x"));
+ tag_init_f64(toaster->data.map.value + 0, -150);
+ tag_init_sym(toaster->data.map.key + 1, sym_1("y"));
+ tag_init_f64(toaster->data.map.value + 1, y);
+ return toaster;
+}
+
+static void toaster_render (s_tag *toaster, s_window_cairo *window,
+ cairo_t *cr, s_sequence *seq)
+{
+ cairo_matrix_t matrix;
+ f64 *x;
+ f64 *y;
+ if (toaster->type == TAG_MAP) {
+ x = &toaster->data.map.value[0].data.f64;
+ y = &toaster->data.map.value[1].data.f64;
+ *x += seq->dt * g_speed_x;
+ *y += seq->dt * g_speed_y;
+ if (*x > window->w || *y < -200) {
+ tag_clean(toaster);
+ toaster->type = TAG_VOID;
+ return;
+ }
+ cairo_get_matrix(cr, &matrix);
+ cairo_translate(cr, *x, *y);
+ cairo_sprite_blit(&g_sprite_toaster,
+ fmod(seq->t * g_sprite_toaster.frame_count,
+ g_sprite_toaster.frame_count),
+ cr, 0, 0);
+ cairo_set_matrix(cr, &matrix);
+ }
+}
+
+bool toasters_load (s_sequence *seq)
+{
+ s_map *map;
+ tag_map(&seq->tag, 2);
+ map = &seq->tag.data.map;
+ tag_init_sym( map->key + 0, sym_1("toasters"));
+ tag_init_list(map->value + 0, NULL);
+ tag_init_sym( map->key + 1, sym_1("toasts"));
+ tag_init_list(map->value + 1, NULL);
+ return true;
+}
+
+bool toasters_render (s_sequence *seq)
+{
+ cairo_t *cr;
+ s_list **toasters;
+ s_list **toasts;
+ s_window_cairo *window;
+ window = seq->window;
+ cr = window->cr;
+ cairo_set_source_rgb(cr, 0.7, 0.95, 1.0);
+ cairo_rectangle(cr, 0, 0, window->w, window->h);
+ cairo_fill(cr);
+ /* io_inspect(&seq->tag); */
+ if (seq->tag.type == TAG_MAP) {
+ toasters = &seq->tag.data.map.value[0].data.list;
+ toasts = &seq->tag.data.map.value[1].data.list;
+ toasters_render_toasts(toasts, window, cr, seq);
+ toasters_render_toasters(toasters, window, cr, seq);
+ }
+ return true;
+}
+
+bool toasters_render_toasts (s_list **toasts, s_window_cairo *window,
+ cairo_t *cr, s_sequence *seq)
+{
+ s_list *i;
+ s_list *j;
+ s_map *map;
+ s_list **t = NULL;
+ f64 x;
+ f64 y;
+ assert(toasts);
+ assert(window);
+ assert(cr);
+ assert(seq);
+ y = window->w * g_speed_y / g_speed_x - 210;
+ if (*toasts && (*toasts)->tag.type == TAG_MAP) {
+ t = &(*toasts)->tag.data.map.value[0].data.list;
+ y = (*toasts)->tag.data.map.value[1].data.f64;
+ }
+ while (y < window->h - 100) {
+ y += 170.0;
+ *toasts = list_new_map(2, *toasts);
+ map = &(*toasts)->tag.data.map;
+ tag_init_sym(map->key + 0, sym_1("toasts"));
+ tag_init_list(map->value + 0, NULL);
+ tag_init_sym(map->key + 1, sym_1("y"));
+ tag_init_f64(map->value + 1, y);
+ }
+ i = *toasts;
+ while (i) {
+ if (i->tag.type == TAG_MAP) {
+ t = &i->tag.data.map.value[0].data.list;
+ y = i->tag.data.map.value[1].data.f64;
+ x = 0.0;
+ if (*t && (*t)->tag.type == TAG_MAP)
+ x = (*t)->tag.data.map.value[0].data.f64;
+ if (x < window->w - 160.0) {
+ *t = list_new(*t);
+ toast_init(&(*t)->tag, window->w, y);
+ }
+ list_remove_void(t);
+ j = *t;
+ while (j) {
+ toast_render(&j->tag, window, cr, seq);
+ j = list_next(j);
+ }
+ }
+ i = list_next(i);
+ }
+ return true;
+}
+
+bool toasters_render_toasters (s_list **toasters,
+ s_window_cairo *window, cairo_t *cr,
+ s_sequence *seq)
+{
+ s_list *i;
+ s_list *j;
+ s_map *map;
+ s_list **t = NULL;
+ f64 x;
+ f64 y;
+ assert(toasters);
+ assert(window);
+ assert(cr);
+ assert(seq);
+ /* io_inspect_list((const s_list **) toasters); */
+ y = -100.0;
+ if (*toasters && (*toasters)->tag.type == TAG_MAP) {
+ t = &(*toasters)->tag.data.map.value[0].data.list;
+ y = (*toasters)->tag.data.map.value[1].data.f64;
+ }
+ while (y < window->h - window->w * g_speed_y / g_speed_x) {
+ y += 170.0;
+ *toasters = list_new_map(2, *toasters);
+ map = &(*toasters)->tag.data.map;
+ tag_init_sym(map->key + 0, sym_1("toasters"));
+ tag_init_list(map->value + 0, NULL);
+ tag_init_sym(map->key + 1, sym_1("y"));
+ tag_init_f64(map->value + 1, y);
+ }
+ i = *toasters;
+ while (i) {
+ if (i->tag.type == TAG_MAP) {
+ t = &i->tag.data.map.value[0].data.list;
+ y = i->tag.data.map.value[1].data.f64;
+ x = 1000.0;
+ if (*t && (*t)->tag.type == TAG_MAP)
+ x = (*t)->tag.data.map.value[0].data.f64;
+ if (x > 60.0) {
+ *t = list_new(*t);
+ toaster_init(&(*t)->tag, y);
+ }
+ list_remove_void(t);
+ j = *t;
+ while (j) {
+ toaster_render(&j->tag, window, cr, seq);
+ j = list_next(j);
+ }
+ }
+ i = list_next(i);
+ }
+ return true;
+}
+
+bool toasters_unload (s_sequence *seq)
+{
+ (void) seq;
+ return true;
+}
diff --git a/window/cairo/demo/toasters.h b/window/cairo/demo/toasters.h
new file mode 100644
index 0000000..4ea1fae
--- /dev/null
+++ b/window/cairo/demo/toasters.h
@@ -0,0 +1,25 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 TOASTERS_H
+#define TOASTERS_H
+
+#include "../types.h"
+
+extern s_cairo_sprite g_sprite_toast;
+extern s_cairo_sprite g_sprite_toaster;
+
+bool toasters_load (s_sequence *seq);
+bool toasters_render (s_sequence *seq);
+bool toasters_unload (s_sequence *seq);
+
+#endif /* TOASTERS_H */
diff --git a/window/cairo/demo/update_sources b/window/cairo/demo/update_sources
new file mode 100755
index 0000000..0c17b11
--- /dev/null
+++ b/window/cairo/demo/update_sources
@@ -0,0 +1,28 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+. ../../../config.subr
+
+echo "$PWD/update_sources"
+
+echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
+echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
+
+HEADERS="$(ls *.h | grep -v '^config.h$')"
+sources HEADERS "$HEADERS"
+
+SOURCES="$(ls *.c)"
+sources SOURCES "$SOURCES"
+
+update_sources_mk
+update_sources_sh
diff --git a/window/cairo/demo/window_cairo_demo.c b/window/cairo/demo/window_cairo_demo.c
new file mode 100644
index 0000000..b91f9ba
--- /dev/null
+++ b/window/cairo/demo/window_cairo_demo.c
@@ -0,0 +1,184 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <stdlib.h>
+#include <libkc3/kc3.h>
+#include <xkbcommon/xkbcommon.h>
+#include "../../window.h"
+#include "../cairo_font.h"
+#include "../cairo_sprite.h"
+#include "../cairo_text.h"
+#include "../window_cairo.h"
+#include "window_cairo_demo.h"
+#include "bg_rect.h"
+#include "lightspeed.h"
+#include "toasters.h"
+#include "flies.h"
+#include "mandelbrot_f128.h"
+
+s_cairo_font g_font_computer_modern = {0};
+s_cairo_font g_font_courier_new = {0};
+
+bool window_cairo_demo_button (s_window_cairo *window, u8 button,
+ sw x, sw y)
+{
+ assert(window);
+ (void) window;
+ io_write_1("kc3_window_cairo_demo_button: ");
+ io_inspect_u8(&button);
+ io_write_1(" (");
+ io_inspect_sw(&x);
+ io_write_1(", ");
+ io_inspect_sw(&y);
+ io_puts(")");
+ if (window->seq->button &&
+ ! window->seq->button(window->seq, button, x, y))
+ return false;
+ return true;
+}
+
+bool window_cairo_demo_key (s_window_cairo *window, uw keysym)
+{
+ char keysym_name[64];
+ assert(window);
+ (void) window;
+ switch (keysym) {
+ case XKB_KEY_Escape:
+ case XKB_KEY_q:
+ g_kc3_exit_code = 0;
+ return false;
+ case XKB_KEY_Left:
+ if (! window_set_sequence_pos((s_window *) window,
+ (window->sequence_pos +
+ window->sequence_count - 1) %
+ window->sequence_count))
+ return false;
+ break;
+ case XKB_KEY_Right:
+ if (! window_set_sequence_pos((s_window *) window,
+ (window->sequence_pos + 1) %
+ window->sequence_count))
+ return false;
+ break;
+ default:
+ xkb_keysym_get_name(keysym, keysym_name, sizeof(keysym_name));
+ io_write_1("kc3_window_cairo_demo_key: ");
+ io_inspect_uw(&keysym);
+ io_write_1(" ");
+ io_puts(keysym_name);
+ }
+ return true;
+}
+
+bool window_cairo_demo_load (s_window_cairo *window)
+{
+ assert(window);
+ if (window->sequence_count != WINDOW_CAIRO_DEMO_SEQUENCE_COUNT) {
+ err_write_1("window_cairo_demo_load: window->sequence_count = ");
+ err_inspect_uw(&window->sequence_count);
+ err_write_1("\n");
+ assert(window->sequence_count == WINDOW_CAIRO_DEMO_SEQUENCE_COUNT);
+ return false;
+ }
+ if (! cairo_font_init(&g_font_courier_new,
+ "fonts/Courier New/Courier New.ttf"))
+ return false;
+ sequence_init(window->sequence, 8.0, "01. Background rectangles",
+ bg_rect_load, bg_rect_render, bg_rect_unload, window);
+ sequence_init(window->sequence + 1, 20.0, "02. Lightspeed",
+ lightspeed_load, lightspeed_render, lightspeed_unload,
+ window);
+ if (! cairo_sprite_init(&g_sprite_toaster, "img/flaps.png",
+ 4, 1, 4))
+ return false;
+ if (! cairo_sprite_init(&g_sprite_toast, "img/toast.png",
+ 1, 1, 1))
+ return false;
+ sequence_init(window->sequence + 2, 60.0, "03. Toasters",
+ toasters_load, toasters_render, toasters_unload,
+ window);
+ if (! cairo_sprite_init(&g_sprite_fly, "img/fly-noto.png",
+ 1, 1, 1))
+ return false;
+ if (! cairo_sprite_init(&g_sprite_dead_fly, "img/fly-dead.png",
+ 1, 1, 1))
+ return false;
+ sequence_init(window->sequence + 3, 60.0, "04. Flies",
+ flies_load, flies_render, flies_unload, window);
+ sequence_init(window->sequence + 4, 3600.0, "05. Mandelbrot (f128)",
+ mandelbrot_f128_load, mandelbrot_f128_render,
+ mandelbrot_f128_unload, window);
+ window->sequence[4].button = mandelbrot_f128_button;
+ window_set_sequence_pos((s_window *) window, 0);
+ return true;
+}
+
+bool window_cairo_demo_render (s_window_cairo *window)
+{
+ cairo_t *cr;
+ s_sequence *seq;
+ cairo_text_extents_t te;
+ assert(window);
+ cr = window->cr;
+ assert(cr);
+ if (! window_animate((s_window *) window))
+ return false;
+ seq = window->sequence + window->sequence_pos;
+ if (! seq->render(seq))
+ return false;
+ /* text */
+ cairo_identity_matrix(cr);
+ cairo_set_font_size(cr, 20);
+ cairo_set_font(cr, &g_font_courier_new);
+ cairo_text_extents(cr, seq->title, &te);
+ cairo_text_outline(cr, 20.0, window->h - te.height - te.y_bearing - 20,
+ seq->title);
+ /* progress bar */
+ cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
+ cairo_rectangle(cr, 19, window->h - 12,
+ (window->w - 40.0) * seq->t / seq->duration + 2,
+ 4);
+ cairo_fill(cr);
+ cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
+ cairo_rectangle(cr, 20, window->h - 11,
+ (window->w - 40.0) * seq->t / seq->duration,
+ 2);
+ cairo_fill(cr);
+ /* fps */
+ char fps[32];
+ snprintf(fps, sizeof(fps), "%f", (f64) seq->frame / seq->t);
+ cairo_text_extents(cr, fps, &te);
+ cairo_text_outline(cr, 20.0, 20.0 + te.height, fps);
+ return true;
+}
+
+bool window_cairo_demo_resize (s_window_cairo *window,
+ uw w, uw h)
+{
+ assert(window);
+ (void) window;
+ (void) w;
+ (void) h;
+ return true;
+}
+
+void window_cairo_demo_unload (s_window_cairo *window)
+{
+ assert(window);
+ (void) window;
+ cairo_font_clean(&g_font_courier_new);
+ cairo_sprite_clean(&g_sprite_toaster);
+ cairo_sprite_clean(&g_sprite_toast);
+ cairo_sprite_clean(&g_sprite_fly);
+ cairo_sprite_clean(&g_sprite_dead_fly);
+}
diff --git a/window/cairo/demo/window_cairo_demo.h b/window/cairo/demo/window_cairo_demo.h
new file mode 100644
index 0000000..8c48aa7
--- /dev/null
+++ b/window/cairo/demo/window_cairo_demo.h
@@ -0,0 +1,31 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_DEMO_H
+#define LIBKC3_WINDOW_CAIRO_DEMO_H
+
+#include "../types.h"
+
+#define WINDOW_CAIRO_DEMO_SEQUENCE_COUNT 5
+
+extern s_cairo_font g_font_computer_modern;
+extern s_cairo_font g_font_courier_new;
+
+bool window_cairo_demo_button (s_window_cairo *window, u8 button,
+ sw x, sw y);
+bool window_cairo_demo_key (s_window_cairo *window, uw keysym);
+bool window_cairo_demo_load (s_window_cairo *window);
+bool window_cairo_demo_render (s_window_cairo *window);
+bool window_cairo_demo_resize (s_window_cairo *window, uw w, uw h);
+void window_cairo_demo_unload (s_window_cairo *window);
+
+#endif /* LIBKC3_WINDOW_CAIRO_DEMO_H */
diff --git a/window/cairo/quartz/Makefile b/window/cairo/quartz/Makefile
new file mode 100644
index 0000000..9e00c8f
--- /dev/null
+++ b/window/cairo/quartz/Makefile
@@ -0,0 +1,85 @@
+## kc3
+## Copyright 2022-2024 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.
+
+CLEANFILES = *.a *.gcno *.la .libs *.lo *.o
+
+CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
+
+CLEANFILES += ${CLEANFILES_COV}
+
+DISTCLEANFILES = ${CLEANFILES} config.h config.mk
+
+build: libkc3_window_cairo_quartz.la
+ ${MAKE} -C demo build
+
+all:
+ ${MAKE} build
+ if ${HAVE_GCOV}; then ${MAKE} cov; fi
+ ${MAKE} debug
+ if ${HAVE_ASAN}; then ${MAKE} asan; fi
+
+asan: libkc3_window_cairo_quartz_asan.la
+ ${MAKE} -C demo asan
+
+clean:
+ rm -rf ${CLEANFILES}
+ ${MAKE} -C demo clean
+
+clean_cov:
+ rm -rf ${CLEANFILES_COV}
+ ${MAKE} -C demo clean_cov
+
+cov: libkc3_window_cairo_quartz_cov.la
+ ${MAKE} -C demo cov
+
+debug: libkc3_window_cairo_quartz_debug.la
+ ${MAKE} -C demo debug
+
+demo: build
+ ${MAKE} -C demo demo
+
+demo_debug: debug
+ ${MAKE} -C demo demo_debug
+
+distclean:
+ rm -rf ${DISTCLEANFILES}
+ ${MAKE} -C demo distclean
+
+gdb_demo: debug
+ ${MAKE} -C demo gdb_demo
+
+lldb_demo: debug
+ ${MAKE} -C demo lldb_demo
+
+test: build
+ ${MAKE} -C demo test
+
+update_sources:
+ ./update_sources
+
+.PHONY: \
+ all \
+ asan \
+ build \
+ clean \
+ cov \
+ debug \
+ demo \
+ distclean \
+ gdb_demo \
+ gen \
+ install \
+ test \
+ update_sources
+
+include config.mk
+include sources.mk
diff --git a/window/cairo/quartz/configure b/window/cairo/quartz/configure
new file mode 100755
index 0000000..bc1d544
--- /dev/null
+++ b/window/cairo/quartz/configure
@@ -0,0 +1,125 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+set -e
+
+echo "$PWD/configure"
+
+export SRC_TOP="$(dirname "$PWD")"
+
+. ../../../config.subr
+
+LIB=libkc3_window_cairo_quartz.la
+LIB_ASAN=libkc3_window_cairo_quartz_asan.la
+LIB_COV=libkc3_window_cairo_quartz_cov.la
+LIB_DEBUG=libkc3_window_cairo_quartz_debug.la
+
+echo "LIB = $LIB" >> ${CONFIG_MK}
+echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
+echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
+echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
+
+. ./sources.sh
+
+OBJECTS="$(c2ext .main.lo "$SOURCES")"
+OBJECTS="$OBJECTS $(objc2ext .main.lo "$OBJC_SOURCES")"
+echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
+
+OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
+OBJECTS_ASAN="$OBJECTS_ASAN $(objc2ext .asan.lo "$OBJC_SOURCES")"
+echo "OBJECTS_ASAN = $OBJECTS_ASAN" >> ${CONFIG_MK}
+
+OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
+OBJECTS_COV="$OBJECTS_COV $(objc2ext .cov.lo "$OBJC_SOURCES")"
+echo "OBJECTS_COV = $OBJECTS_COV" >> ${CONFIG_MK}
+
+OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
+OBJECTS_DEBUG="$OBJECTS_DEBUG $(objc2ext .debug.lo "$OBJC_SOURCES")"
+echo "OBJECTS_DEBUG = $OBJECTS_DEBUG" >> ${CONFIG_MK}
+
+# Common config for all targets
+CPPFLAGS="$CPPFLAGS -I../../.."
+CFLAGS="$CFLAGS -W -Wall -Werror -std=c11 -pedantic -pipe"
+OBJCFLAGS="$CFLAGS -W -Wall -Werror"
+LDFLAGS="--shared $LDFLAGS"
+LIBS="$LIBS"
+config_asan
+config_gnu
+config_i386
+pkg_config cairo
+pkg_config cairo-ft
+config_lib COCOA -framework Cocoa
+pkg_config libffi
+pkg_config libmd
+pkg_config xkbcommon
+
+# Asan config
+CPPFLAGS_ASAN="$CPPFLAGS"
+CFLAGS_ASAN="$CFLAGS -fsanitize=address -O1 -fno-omit-frame-pointer -g"
+LDFLAGS_ASAN="$LDFLAGS"
+LOCAL_LIBS_ASAN="../libkc3_window_cairo_asan.la"
+LIBS_ASAN="$LOCAL_LIBS_ASAN $LIBS"
+
+# Coverage config
+CPPFLAGS_COV="$CPPFLAGS"
+CFLAGS_COV="$CFLAGS -ftest-coverage -fprofile-arcs -fprofile-generate"
+LDFLAGS_COV="$LDFLAGS --coverage"
+LOCAL_LIBS_COV="../libkc3_window_cairo_cov.la"
+LIBS_COV="$LOCAL_LIBS_COV $LIBS"
+
+# Debug config
+CPPFLAGS_DEBUG="$CPPFLAGS"
+CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
+LDFLAGS_DEBUG="$LDFLAGS"
+LOCAL_LIBS_DEBUG="../libkc3_window_cairo_debug.la"
+LIBS_DEBUG="$LOCAL_LIBS_DEBUG $LIBS"
+
+# Main config
+DEFAULT_CFLAGS="-O2 -fPIC"
+if [ "x$ENV_CFLAGS" = "x" ]; then
+ CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
+fi
+CFLAGS="$CFLAGS -DNDEBUG"
+LOCAL_LIBS="../libkc3_window_cairo.la"
+LIBS="$LOCAL_LIBS $LIBS"
+
+echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
+echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
+echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
+echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
+echo "LIBS = $LIBS" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
+echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
+echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
+
+update_build
+update_build_objc
+update_build_lib
+
+build_lo
+build_lo_objc
+build_lib
+
+update_config_mk
+env_reset
+
+config_subdirs demo
diff --git a/window/cairo/quartz/demo.xcodeproj/project.pbxproj b/window/cairo/quartz/demo.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..ac58d89
--- /dev/null
+++ b/window/cairo/quartz/demo.xcodeproj/project.pbxproj
@@ -0,0 +1,410 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 56;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 2A5416E32B03D3E100E42968 /* c3_window_cairo_quartz_demo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5416E02B03D3E100E42968 /* c3_window_cairo_quartz_demo.swift */; };
+ 2A5416F02B03E86C00E42968 /* c3_window_cairo_quartz_demo_bridging_header.h in Sources */ = {isa = PBXBuildFile; fileRef = 2A5416E12B03D3E100E42968 /* c3_window_cairo_quartz_demo_bridging_header.h */; };
+ 2A5416F12B03E86C00E42968 /* content_view.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5416E52B03D43200E42968 /* content_view.swift */; };
+ 2A5416F22B03E86C00E42968 /* custom_cairo_swiftui_view.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5416E62B03D43200E42968 /* custom_cairo_swiftui_view.swift */; };
+ 2A5416F32B03E86C00E42968 /* custom_cairo_view.h in Sources */ = {isa = PBXBuildFile; fileRef = 2A5416E72B03D43200E42968 /* custom_cairo_view.h */; };
+ 2A5416F42B03E86C00E42968 /* custom_cairo_view.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A5416E42B03D43200E42968 /* custom_cairo_view.m */; };
+ 2A5416F92B03E88E00E42968 /* libc3_window_cairo_quartz.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A5416F82B03E88E00E42968 /* libc3_window_cairo_quartz.0.dylib */; };
+ 2A5416FB2B03E95B00E42968 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2A5416FA2B03E95B00E42968 /* Assets.xcassets */; };
+ 2A5416FC2B03F73D00E42968 /* libc3_window_cairo_quartz.0.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 2A5416F82B03E88E00E42968 /* libc3_window_cairo_quartz.0.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
+ 2A5417002B0403FB00E42968 /* Preview Content in Resources */ = {isa = PBXBuildFile; fileRef = 2A5416FE2B0403FB00E42968 /* Preview Content */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 2A5416FD2B03F73D00E42968 /* Embed Libraries */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 10;
+ files = (
+ 2A5416FC2B03F73D00E42968 /* libc3_window_cairo_quartz.0.dylib in Embed Libraries */,
+ );
+ name = "Embed Libraries";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 2A5416C32B038F6100E42968 /* c3_window_cairo_quartz_demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = c3_window_cairo_quartz_demo.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2A5416E02B03D3E100E42968 /* c3_window_cairo_quartz_demo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = c3_window_cairo_quartz_demo.swift; path = demo/c3_window_cairo_quartz_demo.swift; sourceTree = "<group>"; };
+ 2A5416E12B03D3E100E42968 /* c3_window_cairo_quartz_demo_bridging_header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = c3_window_cairo_quartz_demo_bridging_header.h; path = demo/c3_window_cairo_quartz_demo_bridging_header.h; sourceTree = "<group>"; };
+ 2A5416E22B03D3E100E42968 /* c3_window_cairo_quartz_demo.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; name = c3_window_cairo_quartz_demo.entitlements; path = demo/c3_window_cairo_quartz_demo.entitlements; sourceTree = "<group>"; };
+ 2A5416E42B03D43200E42968 /* custom_cairo_view.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = custom_cairo_view.m; sourceTree = "<group>"; };
+ 2A5416E52B03D43200E42968 /* content_view.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = content_view.swift; sourceTree = "<group>"; };
+ 2A5416E62B03D43200E42968 /* custom_cairo_swiftui_view.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = custom_cairo_swiftui_view.swift; sourceTree = "<group>"; };
+ 2A5416E72B03D43200E42968 /* custom_cairo_view.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = custom_cairo_view.h; sourceTree = "<group>"; };
+ 2A5416F82B03E88E00E42968 /* libc3_window_cairo_quartz.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libc3_window_cairo_quartz.0.dylib; path = .libs/libc3_window_cairo_quartz.0.dylib; sourceTree = "<group>"; };
+ 2A5416FA2B03E95B00E42968 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = demo/Assets.xcassets; sourceTree = "<group>"; };
+ 2A5416FE2B0403FB00E42968 /* Preview Content */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "Preview Content"; path = "demo/Preview Content"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 2A5416C02B038F6100E42968 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2A5416F92B03E88E00E42968 /* libc3_window_cairo_quartz.0.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 2A5416BA2B038F6100E42968 = {
+ isa = PBXGroup;
+ children = (
+ 2A5416FA2B03E95B00E42968 /* Assets.xcassets */,
+ 2A5416FE2B0403FB00E42968 /* Preview Content */,
+ 2A5416E12B03D3E100E42968 /* c3_window_cairo_quartz_demo_bridging_header.h */,
+ 2A5416E52B03D43200E42968 /* content_view.swift */,
+ 2A5416E62B03D43200E42968 /* custom_cairo_swiftui_view.swift */,
+ 2A5416E72B03D43200E42968 /* custom_cairo_view.h */,
+ 2A5416E42B03D43200E42968 /* custom_cairo_view.m */,
+ 2A5416E22B03D3E100E42968 /* c3_window_cairo_quartz_demo.entitlements */,
+ 2A5416E02B03D3E100E42968 /* c3_window_cairo_quartz_demo.swift */,
+ 2A5416C42B038F6100E42968 /* Products */,
+ 2A5416DD2B03B3C900E42968 /* Frameworks */,
+ );
+ sourceTree = "<group>";
+ };
+ 2A5416C42B038F6100E42968 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 2A5416C32B038F6100E42968 /* c3_window_cairo_quartz_demo.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 2A5416DD2B03B3C900E42968 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 2A5416F82B03E88E00E42968 /* libc3_window_cairo_quartz.0.dylib */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 2A5416C22B038F6100E42968 /* c3_window_cairo_quartz_demo */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2A5416D22B038F6200E42968 /* Build configuration list for PBXNativeTarget "c3_window_cairo_quartz_demo" */;
+ buildPhases = (
+ 2A5416BF2B038F6100E42968 /* Sources */,
+ 2A5416C02B038F6100E42968 /* Frameworks */,
+ 2A5416C12B038F6100E42968 /* Resources */,
+ 2A5416FD2B03F73D00E42968 /* Embed Libraries */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = c3_window_cairo_quartz_demo;
+ productName = libc3_window_cairo_quartz;
+ productReference = 2A5416C32B038F6100E42968 /* c3_window_cairo_quartz_demo.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 2A5416BB2B038F6100E42968 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ BuildIndependentTargetsInParallel = 1;
+ LastSwiftUpdateCheck = 1500;
+ LastUpgradeCheck = 1500;
+ TargetAttributes = {
+ 2A5416C22B038F6100E42968 = {
+ CreatedOnToolsVersion = 15.0.1;
+ LastSwiftMigration = 1500;
+ };
+ };
+ };
+ buildConfigurationList = 2A5416BE2B038F6100E42968 /* Build configuration list for PBXProject "demo" */;
+ compatibilityVersion = "Xcode 14.0";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 2A5416BA2B038F6100E42968;
+ productRefGroup = 2A5416C42B038F6100E42968 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 2A5416C22B038F6100E42968 /* c3_window_cairo_quartz_demo */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 2A5416C12B038F6100E42968 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2A5417002B0403FB00E42968 /* Preview Content in Resources */,
+ 2A5416FB2B03E95B00E42968 /* Assets.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 2A5416BF2B038F6100E42968 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2A5416F02B03E86C00E42968 /* c3_window_cairo_quartz_demo_bridging_header.h in Sources */,
+ 2A5416F12B03E86C00E42968 /* content_view.swift in Sources */,
+ 2A5416F22B03E86C00E42968 /* custom_cairo_swiftui_view.swift in Sources */,
+ 2A5416F32B03E86C00E42968 /* custom_cairo_view.h in Sources */,
+ 2A5416F42B03E86C00E42968 /* custom_cairo_view.m in Sources */,
+ 2A5416E32B03D3E100E42968 /* c3_window_cairo_quartz_demo.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 2A5416D02B038F6200E42968 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ 2A5416D12B038F6200E42968 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ MTL_FAST_MATH = YES;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ };
+ name = Release;
+ };
+ 2A5416D32B038F6200E42968 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_ENTITLEMENTS = demo/c3_window_cairo_quartz_demo.entitlements;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_ASSET_PATHS = demo;
+ DEVELOPMENT_TEAM = W4AD54MQ5Q;
+ ENABLE_PREVIEWS = YES;
+ GENERATE_INFOPLIST_FILE = YES;
+ HEADER_SEARCH_PATHS = /opt/homebrew/include;
+ "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
+ "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
+ "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
+ "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
+ "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
+ "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
+ "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
+ "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ IPHONEOS_DEPLOYMENT_TARGET = 17.0;
+ LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
+ "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
+ LIBRARY_SEARCH_PATHS = (
+ /opt/homebrew/lib,
+ /opt/homebrew/Cellar/cairo/1.18.0/lib,
+ "$(PROJECT_DIR)/.libs",
+ );
+ MACOSX_DEPLOYMENT_TARGET = 14.0;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = "kmx.io.c3-window-cairo-quartz-demo";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = auto;
+ STRIP_INSTALLED_PRODUCT = NO;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_OBJC_BRIDGING_HEADER = demo/c3_window_cairo_quartz_demo_bridging_header.h;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 2A5416D42B038F6200E42968 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_ENTITLEMENTS = demo/c3_window_cairo_quartz_demo.entitlements;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_ASSET_PATHS = demo;
+ DEVELOPMENT_TEAM = W4AD54MQ5Q;
+ ENABLE_PREVIEWS = YES;
+ GENERATE_INFOPLIST_FILE = YES;
+ HEADER_SEARCH_PATHS = /opt/homebrew/include;
+ "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
+ "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
+ "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
+ "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
+ "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
+ "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
+ "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
+ "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ IPHONEOS_DEPLOYMENT_TARGET = 17.0;
+ LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
+ "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
+ LIBRARY_SEARCH_PATHS = (
+ /opt/homebrew/lib,
+ /opt/homebrew/Cellar/cairo/1.18.0/lib,
+ "$(PROJECT_DIR)/.libs",
+ );
+ MACOSX_DEPLOYMENT_TARGET = 14.0;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = "kmx.io.c3-window-cairo-quartz-demo";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = auto;
+ STRIP_INSTALLED_PRODUCT = NO;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_OBJC_BRIDGING_HEADER = demo/c3_window_cairo_quartz_demo_bridging_header.h;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 2A5416BE2B038F6100E42968 /* Build configuration list for PBXProject "demo" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2A5416D02B038F6200E42968 /* Debug */,
+ 2A5416D12B038F6200E42968 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 2A5416D22B038F6200E42968 /* Build configuration list for PBXNativeTarget "c3_window_cairo_quartz_demo" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2A5416D32B038F6200E42968 /* Debug */,
+ 2A5416D42B038F6200E42968 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 2A5416BB2B038F6100E42968 /* Project object */;
+}
diff --git a/window/cairo/quartz/demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/window/cairo/quartz/demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/window/cairo/quartz/demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:">
+ </FileRef>
+</Workspace>
diff --git a/window/cairo/quartz/demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/window/cairo/quartz/demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/window/cairo/quartz/demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IDEDidComputeMac32BitWarning</key>
+ <true/>
+</dict>
+</plist>
diff --git a/window/cairo/quartz/demo.xcodeproj/project.xcworkspace/xcuserdata/thodg.xcuserdatad/UserInterfaceState.xcuserstate b/window/cairo/quartz/demo.xcodeproj/project.xcworkspace/xcuserdata/thodg.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..73dbe44
Binary files /dev/null and b/window/cairo/quartz/demo.xcodeproj/project.xcworkspace/xcuserdata/thodg.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/window/cairo/quartz/demo.xcodeproj/xcuserdata/thodg.xcuserdatad/xcschemes/xcschememanagement.plist b/window/cairo/quartz/demo.xcodeproj/xcuserdata/thodg.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 0000000..df532c7
--- /dev/null
+++ b/window/cairo/quartz/demo.xcodeproj/xcuserdata/thodg.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>SchemeUserState</key>
+ <dict>
+ <key>libc3_window_cairo_quartz.xcscheme_^#shared#^_</key>
+ <dict>
+ <key>orderHint</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/window/cairo/quartz/demo/Assets.xcassets/AccentColor.colorset/Contents.json b/window/cairo/quartz/demo/Assets.xcassets/AccentColor.colorset/Contents.json
new file mode 100644
index 0000000..eb87897
--- /dev/null
+++ b/window/cairo/quartz/demo/Assets.xcassets/AccentColor.colorset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "colors" : [
+ {
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/window/cairo/quartz/demo/Assets.xcassets/AppIcon.appiconset/Contents.json b/window/cairo/quartz/demo/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..532cd72
--- /dev/null
+++ b/window/cairo/quartz/demo/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,63 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "1x",
+ "size" : "16x16"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "2x",
+ "size" : "16x16"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "1x",
+ "size" : "32x32"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "2x",
+ "size" : "32x32"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "1x",
+ "size" : "128x128"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "2x",
+ "size" : "128x128"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "1x",
+ "size" : "256x256"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "2x",
+ "size" : "256x256"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "1x",
+ "size" : "512x512"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "2x",
+ "size" : "512x512"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/window/cairo/quartz/demo/Assets.xcassets/Contents.json b/window/cairo/quartz/demo/Assets.xcassets/Contents.json
new file mode 100644
index 0000000..73c0059
--- /dev/null
+++ b/window/cairo/quartz/demo/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/window/cairo/quartz/demo/Makefile b/window/cairo/quartz/demo/Makefile
new file mode 100644
index 0000000..0169654
--- /dev/null
+++ b/window/cairo/quartz/demo/Makefile
@@ -0,0 +1,107 @@
+## kc3
+## Copyright 2022-2024 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.
+
+CLEANFILES = *.a ${APP_PROG} ${APP_PROG_ASAN} ${APP_PROG_COV} \
+ ${APP_PROG_DEBUG} ${PROG} ${PROG_ASAN} ${PROG_COV} ${PROG_DEBUG} \
+ *.css *.gcno *.html *.o .libs *.lo
+
+CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
+CLEANFILES += ${CLEANFILES_COV}
+
+DISTCLEANFILES = ${CLEANFILES} config.mk
+
+IMG_SOURCES = \
+ ../../../../img/flaps.png \
+ ../../../../img/fly-dead.png \
+ ../../../../img/fly-noto.png \
+ ../../../../img/toast.png \
+
+FONT_SOURCES = \
+ ../../../../fonts/Computer\ Modern \
+ ../../../../fonts/Courier\ New \
+
+build:
+ ${MAKE} ${APP_PROG}
+ ${MAKE} ${APP}/Contents/Frameworks
+ rsync -aP ${FONT_SOURCES} ${APP}/Contents/fonts/
+ rsync -aP ${IMG_SOURCES} ${APP}/Contents/img/
+ rsync -aP --delete ../../../../lib ${APP}/Contents/
+
+all:
+ ${MAKE} build
+ if ${HAVE_GCOV}; then ${MAKE} cov; fi
+ ${MAKE} debug
+ if ${HAVE_ASAN}; then ${MAKE} asan; fi
+
+asan:
+ ${MAKE} ${APP_PROG_ASAN}
+ ${MAKE} ${APP_ASAN}/Contents/Frameworks
+ rsync -aP ${FONT_SOURCES} ${APP_ASAN}/Contents/fonts/
+ rsync -aP ${IMG_SOURCES} ${APP_ASAN}/Contents/img/
+ rsync -aP --delete ../../../../lib ${APP_ASAN}/Contents/
+
+clean:
+ rm -rf ${CLEANFILES}
+
+clean_cov:
+ rm -rf ${CLEANFILES_COV}
+
+cov:
+ ${MAKE} ${APP_PROG_COV}
+ ${MAKE} ${APP_COV}/Contents/Frameworks
+ rsync -aP ${FONT_SOURCES} ${APP_COV}/Contents/fonts/
+ rsync -aP ${IMG_SOURCES} ${APP_COV}/Contents/img/
+ rsync -aP --delete ../../../../lib ${APP_COV}/Contents/
+
+debug:
+ ${MAKE} ${APP_PROG_DEBUG}
+ ${MAKE} ${APP_DEBUG}/Contents/Frameworks
+ rsync -aP ${FONT_SOURCES} ${APP_DEBUG}/Contents/fonts/
+ rsync -aP ${IMG_SOURCES} ${APP_DEBUG}/Contents/img/
+ rsync -aP --delete ../../../../lib ${APP_DEBUG}/Contents/
+
+demo: build
+ time ${APP_PROG}
+
+demo_debug: debug
+ time ${APP_PROG_DEBUG}
+
+distclean:
+ rm -rf ${DISTCLEANFILES}
+
+gcovr:
+ gcovr --gcov-executable ${GCOV} --html-details ${PROG}.html
+
+gdb_demo: debug
+ if [ -f ${PROG_DEBUG}.core ]; then gdb .libs/${PROG_DEBUG} ${PROG_DEBUG}.core; else gdb .libs/${PROG_DEBUG}; fi
+
+lldb_demo: debug
+ lldb ${APP_PROG_DEBUG}
+
+install:
+ install -m 755 -d ${prefix}/bin
+ install -m 755 ${PROG} ${prefix}/bin/${PROG}
+
+.PHONY: \
+ all \
+ asan \
+ clean \
+ clean_cov \
+ cov \
+ debug \
+ demo \
+ distclean \
+ gdb_demo \
+ lldb_demo
+
+include config.mk
+include sources.mk
diff --git a/window/cairo/quartz/demo/Preview Content/Preview Assets.xcassets/Contents.json b/window/cairo/quartz/demo/Preview Content/Preview Assets.xcassets/Contents.json
new file mode 100644
index 0000000..73c0059
--- /dev/null
+++ b/window/cairo/quartz/demo/Preview Content/Preview Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/window/cairo/quartz/demo/c3_window_cairo_quartz_demo.app/Contents/Info.plist b/window/cairo/quartz/demo/c3_window_cairo_quartz_demo.app/Contents/Info.plist
new file mode 100644
index 0000000..e17dd6f
--- /dev/null
+++ b/window/cairo/quartz/demo/c3_window_cairo_quartz_demo.app/Contents/Info.plist
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleExecutable</key>
+ <string>c3_window_cairo_quartz_demo</string>
+ <key>CFBundleIconFile</key>
+ <string>c3</string>
+ <key>CFBundleIdentifier</key>
+ <string>io.kmx.c3-window-cairo-quartz-demo</string>
+</dict>
+</plist>
diff --git a/window/cairo/quartz/demo/c3_window_cairo_quartz_demo.app/Contents/Resources/c3.icns b/window/cairo/quartz/demo/c3_window_cairo_quartz_demo.app/Contents/Resources/c3.icns
new file mode 100644
index 0000000..377277a
Binary files /dev/null and b/window/cairo/quartz/demo/c3_window_cairo_quartz_demo.app/Contents/Resources/c3.icns differ
diff --git a/window/cairo/quartz/demo/c3_window_cairo_quartz_demo.entitlements b/window/cairo/quartz/demo/c3_window_cairo_quartz_demo.entitlements
new file mode 100644
index 0000000..f2ef3ae
--- /dev/null
+++ b/window/cairo/quartz/demo/c3_window_cairo_quartz_demo.entitlements
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.security.app-sandbox</key>
+ <true/>
+ <key>com.apple.security.files.user-selected.read-only</key>
+ <true/>
+</dict>
+</plist>
diff --git a/window/cairo/quartz/demo/c3_window_cairo_quartz_demo_asan.app/Contents/Info.plist b/window/cairo/quartz/demo/c3_window_cairo_quartz_demo_asan.app/Contents/Info.plist
new file mode 100644
index 0000000..bf9ee0e
--- /dev/null
+++ b/window/cairo/quartz/demo/c3_window_cairo_quartz_demo_asan.app/Contents/Info.plist
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleExecutable</key>
+ <string>c3_window_cairo_quartz_demo_asan</string>
+ <key>CFBundleIconFile</key>
+ <string>c3</string>
+ <key>CFBundleIdentifier</key>
+ <string>io.kmx.c3-window-cairo-quartz-demo-asan</string>
+</dict>
+</plist>
diff --git a/window/cairo/quartz/demo/c3_window_cairo_quartz_demo_asan.app/Contents/Resources/c3.icns b/window/cairo/quartz/demo/c3_window_cairo_quartz_demo_asan.app/Contents/Resources/c3.icns
new file mode 100644
index 0000000..377277a
Binary files /dev/null and b/window/cairo/quartz/demo/c3_window_cairo_quartz_demo_asan.app/Contents/Resources/c3.icns differ
diff --git a/window/cairo/quartz/demo/c3_window_cairo_quartz_demo_cov.app/Contents/Info.plist b/window/cairo/quartz/demo/c3_window_cairo_quartz_demo_cov.app/Contents/Info.plist
new file mode 100644
index 0000000..bd1c234
--- /dev/null
+++ b/window/cairo/quartz/demo/c3_window_cairo_quartz_demo_cov.app/Contents/Info.plist
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleExecutable</key>
+ <string>c3_window_cairo_quartz_demo_cov</string>
+ <key>CFBundleIconFile</key>
+ <string>c3</string>
+ <key>CFBundleIdentifier</key>
+ <string>io.kmx.c3-window-cairo-quartz-demo-cov</string>
+</dict>
+</plist>
diff --git a/window/cairo/quartz/demo/c3_window_cairo_quartz_demo_cov.app/Contents/Resources/c3_window_cairo_quartz_demo.icns b/window/cairo/quartz/demo/c3_window_cairo_quartz_demo_cov.app/Contents/Resources/c3_window_cairo_quartz_demo.icns
new file mode 100644
index 0000000..377277a
Binary files /dev/null and b/window/cairo/quartz/demo/c3_window_cairo_quartz_demo_cov.app/Contents/Resources/c3_window_cairo_quartz_demo.icns differ
diff --git a/window/cairo/quartz/demo/c3_window_cairo_quartz_demo_debug.app/Contents/Info.plist b/window/cairo/quartz/demo/c3_window_cairo_quartz_demo_debug.app/Contents/Info.plist
new file mode 100644
index 0000000..853f6b8
--- /dev/null
+++ b/window/cairo/quartz/demo/c3_window_cairo_quartz_demo_debug.app/Contents/Info.plist
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleExecutable</key>
+ <string>c3_window_cairo_quartz_demo_debug</string>
+ <key>CFBundleIconFile</key>
+ <string>c3</string>
+ <key>CFBundleIdentifier</key>
+ <string>io.kmx.c3-window-cairo-quartz-demo-debug</string>
+</dict>
+</plist>
diff --git a/window/cairo/quartz/demo/c3_window_cairo_quartz_demo_debug.app/Contents/Resources/c3.icns b/window/cairo/quartz/demo/c3_window_cairo_quartz_demo_debug.app/Contents/Resources/c3.icns
new file mode 100644
index 0000000..377277a
Binary files /dev/null and b/window/cairo/quartz/demo/c3_window_cairo_quartz_demo_debug.app/Contents/Resources/c3.icns differ
diff --git a/window/cairo/quartz/demo/configure b/window/cairo/quartz/demo/configure
new file mode 100755
index 0000000..ea435c4
--- /dev/null
+++ b/window/cairo/quartz/demo/configure
@@ -0,0 +1,227 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+set -e
+
+echo "$PWD/configure"
+
+export SRC_TOP="$(dirname "$PWD")"
+
+. ../../../../config.subr
+
+PROG=kc3_window_cairo_quartz_demo
+PROG_ASAN=kc3_window_cairo_quartz_demo_asan
+PROG_COV=kc3_window_cairo_quartz_demo_cov
+PROG_DEBUG=kc3_window_cairo_quartz_demo_debug
+
+echo "PROG = $PROG" >> ${CONFIG_MK}
+echo "PROG_ASAN = $PROG_ASAN" >> ${CONFIG_MK}
+echo "PROG_COV = $PROG_COV" >> ${CONFIG_MK}
+echo "PROG_DEBUG = $PROG_DEBUG" >> ${CONFIG_MK}
+
+APP=kc3_window_cairo_quartz_demo.app
+APP_ASAN=kc3_window_cairo_quartz_demo_asan.app
+APP_COV=kc3_window_cairo_quartz_demo_cov.app
+APP_DEBUG=kc3_window_cairo_quartz_demo_debug.app
+
+echo "APP = $APP" >> ${CONFIG_MK}
+echo "APP_ASAN = ${APP_ASAN}" >> ${CONFIG_MK}
+echo "APP_COV = ${APP_COV}" >> ${CONFIG_MK}
+echo "APP_DEBUG = ${APP_DEBUG}" >> ${CONFIG_MK}
+
+APP_PROG=${APP}/Contents/MacOS/${PROG}
+APP_PROG_ASAN=${APP_ASAN}/Contents/MacOS/${PROG_ASAN}
+APP_PROG_COV=${APP_COV}/Contents/MacOS/${PROG_COV}
+APP_PROG_DEBUG=${APP_DEBUG}/Contents/MacOS/${PROG_DEBUG}
+
+echo "APP_PROG = $APP_PROG" >> ${CONFIG_MK}
+echo "APP_PROG_ASAN = $APP_PROG_ASAN" >> ${CONFIG_MK}
+echo "APP_PROG_COV = $APP_PROG_COV" >> ${CONFIG_MK}
+echo "APP_PROG_DEBUG = $APP_PROG_DEBUG" >> ${CONFIG_MK}
+
+. ./sources.sh
+
+OBJECTS="$(c2ext .main.lo "$SOURCES")"
+echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
+
+OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
+echo "OBJECTS_ASAN = $OBJECTS_ASAN" >> ${CONFIG_MK}
+
+if $HAVE_GCOV; then
+ OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
+ echo "OBJECTS_COV = $OBJECTS_COV" >> ${CONFIG_MK}
+fi
+
+OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
+echo "OBJECTS_DEBUG = $OBJECTS_DEBUG" >> ${CONFIG_MK}
+
+# Common config for all targets
+CPPFLAGS="$CPPFLAGS -I../../../.."
+CFLAGS="$CFLAGS -W -Wall -Werror -std=c11 -pedantic -pipe"
+OBJCFLAGS="$CFLAGS -W -Wall -Werror"
+LDFLAGS="$LDFLAGS -framework Cocoa"
+LIBS="$LIBS"
+config_asan
+config_gnu
+config_i386
+pkg_config cairo
+pkg_config cairo-ft
+pkg_config libffi
+pkg_config libmd
+pkg_config xkbcommon
+
+# Asan config
+CPPFLAGS_ASAN="$CPPFLAGS"
+CFLAGS_ASAN="$CFLAGS -DDEBUG -O1 -g"
+CFLAGS_ASAN="$CFLAGS_ASAN -fsanitize=address -fno-omit-frame-pointer"
+LDFLAGS_ASAN="$LDFLAGS"
+LOCAL_LIBS_ASAN="../../demo/libkc3_window_cairo_demo_asan.la"
+LOCAL_LIBS_ASAN="$LOCAL_LIBS_ASAN ../libkc3_window_cairo_quartz_asan.la"
+LIBS_ASAN="$LOCAL_LIBS_ASAN $LIBS"
+
+# Coverage config
+CPPFLAGS_COV="$CPPFLAGS"
+CFLAGS_COV="$CFLAGS -DDEBUG --coverage"
+LDFLAGS_COV="$LDFLAGS"
+LOCAL_LIBS_COV="../../demo/libkc3_window_cairo_demo_cov.la"
+LOCAL_LIBS_COV="$LOCAL_LIBS_COV ../libkc3_window_cairo_quartz_cov.la"
+LIBS_COV="$LOCAL_LIBS_COV $LIBS"
+
+# Debug config
+CPPFLAGS_DEBUG="$CPPFLAGS"
+CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
+LDFLAGS_DEBUG="$LDFLAGS"
+LOCAL_LIBS_DEBUG="../../demo/libkc3_window_cairo_demo_debug.la"
+LOCAL_LIBS_DEBUG="$LOCAL_LIBS_DEBUG ../libkc3_window_cairo_quartz_debug.la"
+LIBS_DEBUG="$LOCAL_LIBS_DEBUG $LIBS"
+
+# Main config
+DEFAULT_CFLAGS="-O2 -fPIC"
+if [ "x$ENV_CFLAGS" = "x" ]; then
+ CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
+fi
+CFLAGS="$CFLAGS -DNDEBUG"
+LIBKC3=../libkc3/libkc3.la
+LOCAL_LIBS="../../demo/libkc3_window_cairo_demo.la"
+LOCAL_LIBS="$LOCAL_LIBS ../libkc3_window_cairo_quartz.la"
+LIBS="$LOCAL_LIBS $LIBS"
+
+echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
+echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
+echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
+echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
+echo "LIBS = $LIBS" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
+echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
+echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
+
+update_build
+update_build_prog
+
+build_lo
+build_prog
+
+echo >> ${CONFIG_MK}
+echo "${APP_PROG}: ${PROG}" >> ${CONFIG_MK}
+echo " mkdir -p $(dirname $APP_PROG)" >> ${CONFIG_MK}
+echo " cp .libs/${PROG} ${APP_PROG}" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "${APP_PROG_ASAN}: ${PROG_ASAN}" >> ${CONFIG_MK}
+echo " mkdir -p $(dirname $APP_PROG_ASAN)" >> ${CONFIG_MK}
+echo " cp .libs/${PROG_ASAN} ${APP_PROG_ASAN}" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "${APP_PROG_COV}: ${PROG_COV}" >> ${CONFIG_MK}
+echo " mkdir -p $(dirname $APP_PROG_COV)" >> ${CONFIG_MK}
+echo " cp .libs/${PROG_COV} ${APP_PROG_COV}" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "${APP_PROG_DEBUG}: ${PROG_DEBUG}" >> ${CONFIG_MK}
+echo " mkdir -p $(dirname $APP_PROG_DEBUG)" >> ${CONFIG_MK}
+echo " cp .libs/${PROG_DEBUG} ${APP_PROG_DEBUG}" >> ${CONFIG_MK}
+
+BUNDLE_LIBS="../../../../libkc3/.libs/libkc3.0.dylib ../../../.libs/libkc3_window.0.dylib ../../.libs/libkc3_window_cairo.0.dylib ../../demo/.libs/libkc3_window_cairo_demo.0.dylib ../.libs/libkc3_window_cairo_quartz.0.dylib"
+echo >> ${CONFIG_MK}
+echo "${APP}/Contents/Frameworks: ${BUNDLE_LIBS}" >> ${CONFIG_MK}
+echo " mkdir -p ${APP}/Contents/Frameworks" >> ${CONFIG_MK}
+echo " cp ${BUNDLE_LIBS} ${APP}/Contents/Frameworks/" >> ${CONFIG_MK}
+for BUNDLE_LIB in ${BUNDLE_LIBS}; do
+ L=$(basename $BUNDLE_LIB)
+ echo " install_name_tool -id @executable_path/../Frameworks/ ${APP}/Contents/Frameworks/$L" >> ${CONFIG_MK}
+ echo " install_name_tool -change ${LIBDIR}/$L @executable_path/../Frameworks/$L ${APP}/Contents/MacOS/${PROG}" >> ${CONFIG_MK}
+ echo " DEPS=\$\$(otool -L '${BUNDLE_LIB}' | awk '/^\t.+(\/usr\/lib|\/System)/ { next } /^\t/ { print \$\$1 }'); for DEP in \$\${DEPS}; do D=\$\$(basename \"\$\${DEP}\"); if [ -f ${APP}/Contents/Frameworks/\$\$D ]; then install_name_tool -change \$\${DEP} @executable_path/../Frameworks/\$\$D ${APP}/Contents/Frameworks/$L; fi; done" >> ${CONFIG_MK}
+done
+echo >> ${CONFIG_MK}
+echo ".PHONY: \\" >> ${CONFIG_MK}
+echo " ${APP}/Contents/Frameworks \\" >> ${CONFIG_MK}
+echo " ${APP_PROG}" >> ${CONFIG_MK}
+
+BUNDLE_LIBS_ASAN="../../../../libkc3/.libs/libkc3_asan.0.dylib ../../../.libs/libkc3_window_asan.0.dylib ../../.libs/libkc3_window_cairo_asan.0.dylib ../../demo/.libs/libkc3_window_cairo_demo_asan.0.dylib ../.libs/libkc3_window_cairo_quartz_asan.0.dylib"
+echo >> ${CONFIG_MK}
+echo "${APP_ASAN}/Contents/Frameworks: ${BUNDLE_LIBS_ASAN}" >> ${CONFIG_MK}
+echo " mkdir -p ${APP_ASAN}/Contents/Frameworks" >> ${CONFIG_MK}
+echo " cp ${BUNDLE_LIBS_ASAN} ${APP_ASAN}/Contents/Frameworks/" >> ${CONFIG_MK}
+for BUNDLE_LIB in ${BUNDLE_LIBS_ASAN}; do
+ L=$(basename $BUNDLE_LIB)
+ echo " install_name_tool -id @executable_path/../Frameworks/ ${APP_ASAN}/Contents/Frameworks/$L" >> ${CONFIG_MK}
+ echo " install_name_tool -change ${LIBDIR}/$L @executable_path/../Frameworks/$L ${APP_ASAN}/Contents/MacOS/${PROG_ASAN}" >> ${CONFIG_MK}
+ echo " DEPS=\$\$(otool -L '${BUNDLE_LIB}' | awk '/^\t.+(\/usr\/lib|\/System)/ { next } /^\t/ { print \$\$1 }'); for DEP in \$\${DEPS}; do D=\$\$(basename \"\$\${DEP}\"); if [ -f ${APP_ASAN}/Contents/Frameworks/\$\$D ]; then install_name_tool -change \$\${DEP} @executable_path/../Frameworks/\$\$D ${APP_ASAN}/Contents/Frameworks/$L; fi; done" >> ${CONFIG_MK}
+done
+echo >> ${CONFIG_MK}
+echo ".PHONY: \\" >> ${CONFIG_MK}
+echo " ${APP_ASAN}/Contents/Frameworks \\" >> ${CONFIG_MK}
+echo " ${APP_PROG_ASAN}" >> ${CONFIG_MK}
+
+BUNDLE_LIBS_COV="../../../../libkc3/.libs/libkc3_cov.0.dylib ../../../.libs/libkc3_window_cov.0.dylib ../../.libs/libkc3_window_cairo_cov.0.dylib ../../demo/.libs/libkc3_window_cairo_demo_cov.0.dylib ../.libs/libkc3_window_cairo_quartz_cov.0.dylib"
+echo >> ${CONFIG_MK}
+echo "${APP_COV}/Contents/Frameworks: ${BUNDLE_LIBS_COV}" >> ${CONFIG_MK}
+echo " mkdir -p ${APP_COV}/Contents/Frameworks" >> ${CONFIG_MK}
+echo " cp ${BUNDLE_LIBS_COV} ${APP_COV}/Contents/Frameworks/" >> ${CONFIG_MK}
+for BUNDLE_LIB in ${BUNDLE_LIBS_COV}; do
+ L=$(basename $BUNDLE_LIB)
+ echo " install_name_tool -id @executable_path/../Frameworks/ ${APP_COV}/Contents/Frameworks/$L" >> ${CONFIG_MK}
+ echo " install_name_tool -change ${LIBDIR}/$L @executable_path/../Frameworks/$L ${APP_COV}/Contents/MacOS/${PROG}" >> ${CONFIG_MK}
+ echo " DEPS=\$\$(otool -L '${BUNDLE_LIB}' | awk '/^\t.+(\/usr\/lib|\/System)/ { next } /^\t/ { print \$\$1 }'); for DEP in \$\${DEPS}; do D=\$\$(basename \"\$\${DEP}\"); if [ -f ${APP_COV}/Contents/Frameworks/\$\$D ]; then install_name_tool -change \$\${DEP} @executable_path/../Frameworks/\$\$D ${APP_COV}/Contents/Frameworks/$L; fi; done" >> ${CONFIG_MK}
+done
+echo >> ${CONFIG_MK}
+echo ".PHONY: \\" >> ${CONFIG_MK}
+echo " ${APP_COV}/Contents/Frameworks \\" >> ${CONFIG_MK}
+echo " ${APP_PROG}" >> ${CONFIG_MK}
+
+BUNDLE_LIBS_DEBUG="../../../../libkc3/.libs/libkc3_debug.0.dylib ../../../.libs/libkc3_window_debug.0.dylib ../../.libs/libkc3_window_cairo_debug.0.dylib ../../demo/.libs/libkc3_window_cairo_demo_debug.0.dylib ../.libs/libkc3_window_cairo_quartz_debug.0.dylib"
+echo >> ${CONFIG_MK}
+echo "${APP_DEBUG}/Contents/Frameworks: ${BUNDLE_LIBS_DEBUG}" >> ${CONFIG_MK}
+echo " mkdir -p ${APP_DEBUG}/Contents/Frameworks" >> ${CONFIG_MK}
+echo " cp ${BUNDLE_LIBS_DEBUG} ${APP_DEBUG}/Contents/Frameworks/" >> ${CONFIG_MK}
+for BUNDLE_LIB in ${BUNDLE_LIBS_DEBUG}; do
+ L=$(basename $BUNDLE_LIB)
+ echo " install_name_tool -id @executable_path/../Frameworks/ ${APP_DEBUG}/Contents/Frameworks/$L" >> ${CONFIG_MK}
+ echo " install_name_tool -change ${LIBDIR}/$L @executable_path/../Frameworks/$L ${APP_DEBUG}/Contents/MacOS/${PROG_DEBUG}" >> ${CONFIG_MK}
+ echo " DEPS=\$\$(otool -L '${BUNDLE_LIB}' | awk '/^\t.+(\/usr\/lib|\/System)/ { next } /^\t/ { print \$\$1 }'); for DEP in \$\${DEPS}; do D=\$\$(basename \"\$\${DEP}\"); if [ -f ${APP_DEBUG}/Contents/Frameworks/\$\$D ]; then install_name_tool -change \$\${DEP} @executable_path/../Frameworks/\$\$D ${APP_DEBUG}/Contents/Frameworks/$L; fi; done" >> ${CONFIG_MK}
+done
+echo >> ${CONFIG_MK}
+echo ".PHONY: \\" >> ${CONFIG_MK}
+echo " ${APP_DEBUG}/Contents/Frameworks \\" >> ${CONFIG_MK}
+echo " ${APP_PROG_DEBUG}" >> ${CONFIG_MK}
+
+update_config_mk
diff --git a/window/cairo/quartz/demo/demo.xcodeproj/project.pbxproj b/window/cairo/quartz/demo/demo.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..1eedaf0
--- /dev/null
+++ b/window/cairo/quartz/demo/demo.xcodeproj/project.pbxproj
@@ -0,0 +1,354 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 56;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 2A54171E2B052C0300E42968 /* c3_window_cairo_quartz_demo.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A54171D2B052C0300E42968 /* c3_window_cairo_quartz_demo.c */; };
+ 2A5417202B052C6600E42968 /* libc3_window_cairo_quartz.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A54171F2B052C6600E42968 /* libc3_window_cairo_quartz.0.dylib */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 2A54170B2B0528E500E42968 /* c3_window_cairo_quartz_demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = c3_window_cairo_quartz_demo.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2A54171D2B052C0300E42968 /* c3_window_cairo_quartz_demo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = c3_window_cairo_quartz_demo.c; sourceTree = "<group>"; };
+ 2A54171F2B052C6600E42968 /* libc3_window_cairo_quartz.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libc3_window_cairo_quartz.0.dylib; path = ../.libs/libc3_window_cairo_quartz.0.dylib; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 2A5417082B0528E500E42968 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2A5417202B052C6600E42968 /* libc3_window_cairo_quartz.0.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 2A5417022B0528E500E42968 = {
+ isa = PBXGroup;
+ children = (
+ 2A54171F2B052C6600E42968 /* libc3_window_cairo_quartz.0.dylib */,
+ 2A54171D2B052C0300E42968 /* c3_window_cairo_quartz_demo.c */,
+ 2A54170C2B0528E500E42968 /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ 2A54170C2B0528E500E42968 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 2A54170B2B0528E500E42968 /* c3_window_cairo_quartz_demo.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 2A54170A2B0528E500E42968 /* c3_window_cairo_quartz_demo */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2A54171A2B0528E700E42968 /* Build configuration list for PBXNativeTarget "c3_window_cairo_quartz_demo" */;
+ buildPhases = (
+ 2A5417072B0528E500E42968 /* Sources */,
+ 2A5417082B0528E500E42968 /* Frameworks */,
+ 2A5417092B0528E500E42968 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = c3_window_cairo_quartz_demo;
+ productName = c3_window_cairo_quartz_demo;
+ productReference = 2A54170B2B0528E500E42968 /* c3_window_cairo_quartz_demo.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 2A5417032B0528E500E42968 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ BuildIndependentTargetsInParallel = 1;
+ LastSwiftUpdateCheck = 1500;
+ LastUpgradeCheck = 1500;
+ TargetAttributes = {
+ 2A54170A2B0528E500E42968 = {
+ CreatedOnToolsVersion = 15.0.1;
+ };
+ };
+ };
+ buildConfigurationList = 2A5417062B0528E500E42968 /* Build configuration list for PBXProject "demo" */;
+ compatibilityVersion = "Xcode 14.0";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 2A5417022B0528E500E42968;
+ productRefGroup = 2A54170C2B0528E500E42968 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 2A54170A2B0528E500E42968 /* c3_window_cairo_quartz_demo */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 2A5417092B0528E500E42968 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 2A5417072B0528E500E42968 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2A54171E2B052C0300E42968 /* c3_window_cairo_quartz_demo.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 2A5417182B0528E700E42968 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ 2A5417192B0528E700E42968 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ MTL_FAST_MATH = YES;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ };
+ name = Release;
+ };
+ 2A54171B2B0528E700E42968 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_ENTITLEMENTS = c3_window_cairo_quartz_demo.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_ASSET_PATHS = "\"Preview Content\"";
+ DEVELOPMENT_TEAM = W4AD54MQ5Q;
+ ENABLE_HARDENED_RUNTIME = YES;
+ ENABLE_PREVIEWS = YES;
+ GENERATE_INFOPLIST_FILE = YES;
+ "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
+ "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
+ "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
+ "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
+ "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
+ "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
+ "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
+ "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ IPHONEOS_DEPLOYMENT_TARGET = 17.0;
+ LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
+ "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
+ MACOSX_DEPLOYMENT_TARGET = 14.0;
+ MARKETING_VERSION = 1.0;
+ OTHER_CFLAGS = (
+ "-I/opt/homebrew/include",
+ "-I../../../../..",
+ "-I../../../../../libffi/include",
+ );
+ OTHER_LDFLAGS = "-L/opt/homebrew/lib";
+ PRODUCT_BUNDLE_IDENTIFIER = "kmx.io.c3-window-cairo-quartz-demo";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SDKROOT = auto;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 2A54171C2B0528E700E42968 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_ENTITLEMENTS = c3_window_cairo_quartz_demo.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_ASSET_PATHS = "\"Preview Content\"";
+ DEVELOPMENT_TEAM = W4AD54MQ5Q;
+ ENABLE_HARDENED_RUNTIME = YES;
+ ENABLE_PREVIEWS = YES;
+ GENERATE_INFOPLIST_FILE = YES;
+ "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
+ "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
+ "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
+ "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
+ "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
+ "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
+ "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
+ "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ IPHONEOS_DEPLOYMENT_TARGET = 17.0;
+ LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
+ "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
+ MACOSX_DEPLOYMENT_TARGET = 14.0;
+ MARKETING_VERSION = 1.0;
+ OTHER_CFLAGS = (
+ "-I/opt/homebrew/include",
+ "-I../../../../..",
+ "-I../../../../../libffi/include",
+ );
+ OTHER_LDFLAGS = "-L/opt/homebrew/lib";
+ PRODUCT_BUNDLE_IDENTIFIER = "kmx.io.c3-window-cairo-quartz-demo";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SDKROOT = auto;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 2A5417062B0528E500E42968 /* Build configuration list for PBXProject "demo" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2A5417182B0528E700E42968 /* Debug */,
+ 2A5417192B0528E700E42968 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 2A54171A2B0528E700E42968 /* Build configuration list for PBXNativeTarget "c3_window_cairo_quartz_demo" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2A54171B2B0528E700E42968 /* Debug */,
+ 2A54171C2B0528E700E42968 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 2A5417032B0528E500E42968 /* Project object */;
+}
diff --git a/window/cairo/quartz/demo/demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/window/cairo/quartz/demo/demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/window/cairo/quartz/demo/demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:">
+ </FileRef>
+</Workspace>
diff --git a/window/cairo/quartz/demo/demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/window/cairo/quartz/demo/demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/window/cairo/quartz/demo/demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IDEDidComputeMac32BitWarning</key>
+ <true/>
+</dict>
+</plist>
diff --git a/window/cairo/quartz/demo/demo.xcodeproj/xcuserdata/thodg.xcuserdatad/xcschemes/xcschememanagement.plist b/window/cairo/quartz/demo/demo.xcodeproj/xcuserdata/thodg.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 0000000..f4a6f10
--- /dev/null
+++ b/window/cairo/quartz/demo/demo.xcodeproj/xcuserdata/thodg.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>SchemeUserState</key>
+ <dict>
+ <key>c3_window_cairo_quartz_demo.xcscheme_^#shared#^_</key>
+ <dict>
+ <key>orderHint</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/window/cairo/quartz/demo/sources.mk b/window/cairo/quartz/demo/sources.mk
new file mode 100644
index 0000000..27c1b5e
--- /dev/null
+++ b/window/cairo/quartz/demo/sources.mk
@@ -0,0 +1,7 @@
+# sources.mk generated by update_sources
+HEADERS = \
+ "" \
+
+SOURCES = \
+ "window_cairo_quartz_demo.c" \
+
diff --git a/window/cairo/quartz/demo/sources.sh b/window/cairo/quartz/demo/sources.sh
new file mode 100644
index 0000000..26d1842
--- /dev/null
+++ b/window/cairo/quartz/demo/sources.sh
@@ -0,0 +1,3 @@
+# sources.sh generated by update_sources
+HEADERS=' '
+SOURCES='window_cairo_quartz_demo.c '
diff --git a/window/cairo/quartz/demo/update_sources b/window/cairo/quartz/demo/update_sources
new file mode 100755
index 0000000..98e6491
--- /dev/null
+++ b/window/cairo/quartz/demo/update_sources
@@ -0,0 +1,29 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+. ../../../../config.subr
+
+echo "$PWD/update_sources"
+
+echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
+echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
+
+#HEADERS="$(ls *.h | grep -v '^config.h$')"
+HEADERS=
+sources HEADERS "$HEADERS"
+
+SOURCES="$(ls *.c)"
+sources SOURCES "$SOURCES"
+
+update_sources_mk
+update_sources_sh
diff --git a/window/cairo/quartz/demo/window_cairo_quartz_demo.c b/window/cairo/quartz/demo/window_cairo_quartz_demo.c
new file mode 100644
index 0000000..2fe41d6
--- /dev/null
+++ b/window/cairo/quartz/demo/window_cairo_quartz_demo.c
@@ -0,0 +1,43 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <stdio.h>
+#include <stdlib.h>
+#include <cairo/cairo.h>
+#include <libkc3/kc3.h>
+#include "../../../window.h"
+#include "../../demo/window_cairo_demo.h"
+#include "../window_cairo_quartz.h"
+
+int main (int argc, char **argv)
+{
+ sw r = 0;
+ s_window_cairo window;
+ if (! kc3_init(NULL, &argc, &argv))
+ return 1;
+ kc3_window_cairo_init();
+ window_cairo_init(&window, 0, 0, 800, 600,
+ "C3.Window.Cairo.Quartz demo",
+ WINDOW_CAIRO_DEMO_SEQUENCE_COUNT);
+ window.button = window_cairo_demo_button;
+ window.key = window_cairo_demo_key;
+ window.load = window_cairo_demo_load;
+ window.render = window_cairo_demo_render;
+ window.resize = window_cairo_demo_resize;
+ window.unload = window_cairo_demo_unload;
+ if (! window_cairo_quartz_run(&window))
+ r = g_kc3_exit_code;
+ window_cairo_clean(&window);
+ kc3_window_cairo_clean();
+ kc3_clean(NULL);
+ return r;
+}
diff --git a/window/cairo/quartz/quartz_to_xkbcommon.c b/window/cairo/quartz/quartz_to_xkbcommon.c
new file mode 100644
index 0000000..b41f8f9
--- /dev/null
+++ b/window/cairo/quartz/quartz_to_xkbcommon.c
@@ -0,0 +1,89 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/types.h>
+#include <xkbcommon/xkbcommon.h>
+
+u32 quartz_to_xkbcommon (u16 quartz_key)
+{
+ switch (quartz_key) {
+ case 27: return XKB_KEY_Escape;
+ case 63236: return XKB_KEY_F1;
+ case 63237: return XKB_KEY_F2;
+ case 63238: return XKB_KEY_F3;
+ case 63239: return XKB_KEY_F4;
+ case 63240: return XKB_KEY_F5;
+ case 63241: return XKB_KEY_F6;
+ case 63242: return XKB_KEY_F7;
+ case 63243: return XKB_KEY_F8;
+ case 63244: return XKB_KEY_F9;
+ case 63245: return XKB_KEY_F10;
+ case 63246: return XKB_KEY_F11;
+ case 63247: return XKB_KEY_F12;
+ case 96: return XKB_KEY_grave;
+ case 49: return XKB_KEY_1;
+ case 50: return XKB_KEY_2;
+ case 51: return XKB_KEY_3;
+ case 52: return XKB_KEY_4;
+ case 53: return XKB_KEY_5;
+ case 54: return XKB_KEY_6;
+ case 55: return XKB_KEY_7;
+ case 56: return XKB_KEY_8;
+ case 57: return XKB_KEY_9;
+ case 48: return XKB_KEY_0;
+ case 45: return XKB_KEY_minus;
+ case 61: return XKB_KEY_equal;
+ case 127: return XKB_KEY_BackSpace;
+ case 9: return XKB_KEY_Tab;
+ case 97: return XKB_KEY_a;
+ case 98: return XKB_KEY_b;
+ case 99: return XKB_KEY_c;
+ case 100: return XKB_KEY_d;
+ case 101: return XKB_KEY_e;
+ case 102: return XKB_KEY_f;
+ case 103: return XKB_KEY_g;
+ case 104: return XKB_KEY_h;
+ case 105: return XKB_KEY_i;
+ case 106: return XKB_KEY_j;
+ case 107: return XKB_KEY_k;
+ case 108: return XKB_KEY_l;
+ case 109: return XKB_KEY_m;
+ case 110: return XKB_KEY_n;
+ case 111: return XKB_KEY_o;
+ case 112: return XKB_KEY_p;
+ case 113: return XKB_KEY_q;
+ case 114: return XKB_KEY_r;
+ case 115: return XKB_KEY_s;
+ case 116: return XKB_KEY_t;
+ case 117: return XKB_KEY_u;
+ case 118: return XKB_KEY_v;
+ case 119: return XKB_KEY_w;
+ case 120: return XKB_KEY_x;
+ case 121: return XKB_KEY_y;
+ case 122: return XKB_KEY_z;
+ case 91: return XKB_KEY_bracketleft;
+ case 93: return XKB_KEY_bracketright;
+ case 92: return XKB_KEY_backslash;
+ case 59: return XKB_KEY_semicolon;
+ case 39: return XKB_KEY_apostrophe;
+ case 13: return XKB_KEY_Return;
+ case 44: return XKB_KEY_comma;
+ case 46: return XKB_KEY_period;
+ case 47: return XKB_KEY_slash;
+ case 63232: return XKB_KEY_Up;
+ case 63233: return XKB_KEY_Down;
+ case 63234: return XKB_KEY_Left;
+ case 63235: return XKB_KEY_Right;
+ default: break;
+ }
+ return XKB_KEY_NoSymbol;
+}
diff --git a/window/cairo/quartz/quartz_to_xkbcommon.h b/window/cairo/quartz/quartz_to_xkbcommon.h
new file mode 100644
index 0000000..b1283da
--- /dev/null
+++ b/window/cairo/quartz/quartz_to_xkbcommon.h
@@ -0,0 +1,20 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_QUARTZ_QUARTZ_TO_XKBCOMMON_H
+#define LIBKC3_WINDOW_CAIRO_QUARTZ_QUARTZ_TO_XKBCOMMON_H
+
+#include <libkc3/types.h>
+
+u32 quartz_to_xkbcommon (u16 quartz_key);
+
+#endif /* LIBKC3_WINDOW_CAIRO_QUARTZ_QUARTZ_TO_XKBCOMMON_H */
diff --git a/window/cairo/quartz/sources.mk b/window/cairo/quartz/sources.mk
new file mode 100644
index 0000000..b1bdd8a
--- /dev/null
+++ b/window/cairo/quartz/sources.mk
@@ -0,0 +1,18 @@
+# sources.mk generated by update_sources
+HEADERS = \
+ "quartz_to_xkbcommon.h" \
+ "window_cairo_quartz.h" \
+ "window_cairo_quartz_app_delegate.h" \
+ "window_cairo_quartz_view.h" \
+ "window_cairo_quartz_view_controller.h" \
+ "xkbquartz.h" \
+
+SOURCES = \
+ "quartz_to_xkbcommon.c" \
+
+OBJC_SOURCES = \
+ "window_cairo_quartz.m" \
+ "window_cairo_quartz_app_delegate.m" \
+ "window_cairo_quartz_view.m" \
+ "window_cairo_quartz_view_controller.m" \
+
diff --git a/window/cairo/quartz/sources.sh b/window/cairo/quartz/sources.sh
new file mode 100644
index 0000000..03cc583
--- /dev/null
+++ b/window/cairo/quartz/sources.sh
@@ -0,0 +1,4 @@
+# sources.sh generated by update_sources
+HEADERS='quartz_to_xkbcommon.h window_cairo_quartz.h window_cairo_quartz_app_delegate.h window_cairo_quartz_view.h window_cairo_quartz_view_controller.h xkbquartz.h '
+SOURCES='quartz_to_xkbcommon.c '
+OBJC_SOURCES='window_cairo_quartz.m window_cairo_quartz_app_delegate.m window_cairo_quartz_view.m window_cairo_quartz_view_controller.m '
diff --git a/window/cairo/quartz/update_sources b/window/cairo/quartz/update_sources
new file mode 100755
index 0000000..e570876
--- /dev/null
+++ b/window/cairo/quartz/update_sources
@@ -0,0 +1,33 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+. ../../../config.subr
+
+echo "$PWD/update_sources"
+
+echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
+echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
+
+HEADERS="$(ls *.h | grep -v '^config.h$')"
+sources HEADERS "$HEADERS"
+
+SOURCES="$(ls *.c)"
+sources SOURCES "$SOURCES"
+
+OBJC_SOURCES="$(ls *.m)"
+sources OBJC_SOURCES "$OBJC_SOURCES"
+
+update_sources_mk
+update_sources_sh
+
+( cd demo && ./update_sources; )
diff --git a/window/cairo/quartz/window_cairo_quartz.h b/window/cairo/quartz/window_cairo_quartz.h
new file mode 100644
index 0000000..289cd1f
--- /dev/null
+++ b/window/cairo/quartz/window_cairo_quartz.h
@@ -0,0 +1,22 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_QUARTZ_H
+#define LIBKC3_WINDOW_CAIRO_QUARTZ_H
+
+#include <libkc3/types.h>
+#include "../types.h"
+#include "../window_cairo.h"
+
+bool window_cairo_quartz_run (s_window_cairo *window);
+
+#endif /* LIBKC3_WINDOW_CAIRO_XCB_H */
diff --git a/window/cairo/quartz/window_cairo_quartz.m b/window/cairo/quartz/window_cairo_quartz.m
new file mode 100644
index 0000000..04a9dc0
--- /dev/null
+++ b/window/cairo/quartz/window_cairo_quartz.m
@@ -0,0 +1,31 @@
+/* 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.
+ */
+#import <Cocoa/Cocoa.h>
+#import "window_cairo_quartz.h"
+#import "window_cairo_quartz_app_delegate.h"
+
+bool window_cairo_quartz_run (s_window_cairo *window)
+{
+ @autoreleasepool {
+ NSApplication *app = [NSApplication sharedApplication];
+ WindowCairoQuartzAppDelegate *app_delegate = [[WindowCairoQuartzAppDelegate alloc] initWithWindowCairo:window];
+ [app setDelegate:app_delegate];
+ [app run];
+ }
+ return true;
+}
+
+bool window_cairo_run (s_window_cairo *window)
+{
+ return window_cairo_quartz_run(window);
+}
diff --git a/window/cairo/quartz/window_cairo_quartz_app_delegate.h b/window/cairo/quartz/window_cairo_quartz_app_delegate.h
new file mode 100644
index 0000000..005d9ec
--- /dev/null
+++ b/window/cairo/quartz/window_cairo_quartz_app_delegate.h
@@ -0,0 +1,26 @@
+/* kc3
+ * Copyright 2022,2023,2024 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.
+ */
+#import <Cocoa/Cocoa.h>
+#import "../window_cairo.h"
+#import "window_cairo_quartz_view.h"
+
+@interface WindowCairoQuartzAppDelegate : NSObject <NSApplicationDelegate,
+ NSWindowDelegate>
+
+@property (strong, nonatomic) NSView *view;
+@property (strong, nonatomic) NSWindow *window;
+@property (nonatomic, assign) s_window_cairo *window_cairo;
+
+- (instancetype) initWithWindowCairo:(s_window_cairo *) window_cairo;
+
+@end
diff --git a/window/cairo/quartz/window_cairo_quartz_app_delegate.m b/window/cairo/quartz/window_cairo_quartz_app_delegate.m
new file mode 100644
index 0000000..4b7d923
--- /dev/null
+++ b/window/cairo/quartz/window_cairo_quartz_app_delegate.m
@@ -0,0 +1,85 @@
+/* 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.
+ */
+#import "window_cairo_quartz_app_delegate.h"
+#import "window_cairo_quartz_view.h"
+#import "window_cairo_quartz_view_controller.h"
+
+@implementation WindowCairoQuartzAppDelegate
+
+- (instancetype) initWithWindowCairo:(s_window_cairo *)window_cairo {
+ self = [super init];
+ if (self) {
+ self.window_cairo = window_cairo;
+ }
+ return self;
+}
+
+- (void)applicationDidFinishLaunching:(NSNotification *)notification {
+ NSRect frame = NSMakeRect(self.window_cairo->x, self.window_cairo->y,
+ self.window_cairo->w, self.window_cairo->h);
+ self.window = [[NSWindow alloc]
+ initWithContentRect:frame
+ styleMask:(NSWindowStyleMaskTitled |
+ NSWindowStyleMaskClosable |
+ NSWindowStyleMaskResizable)
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ [self.window setDelegate:self];
+ [self.window makeKeyAndOrderFront:nil];
+ [self.window
+ setTitle:[NSString
+ stringWithUTF8String:self.window_cairo->title]];
+
+ WindowCairoQuartzView *view =
+ [[WindowCairoQuartzView alloc]
+ initWithWindowCairo:self.window_cairo];
+ WindowCairoQuartzViewController *view_controller =
+ [[WindowCairoQuartzViewController alloc]
+ initWithCairoView:view];
+ self.view = view;
+ [self.window setContentView:view_controller.view];
+ [self.window setAcceptsMouseMovedEvents:YES];
+ if (! self.window_cairo->load(self.window_cairo)) {
+ [self.window close];
+ [self.window release];
+ [[NSApplication sharedApplication] stop:nil];
+ exit(1);
+ }
+ [NSTimer scheduledTimerWithTimeInterval:0.01
+ target:self
+ selector:@selector(redrawWindow)
+ userInfo:nil
+ repeats:YES];
+}
+
+- (void)redrawWindow {
+ [self.view setNeedsDisplay:YES];
+}
+
+- (void)windowDidResize:(NSNotification *)notification {
+ printf("windowDidResize\n");
+ NSWindow *window = (NSWindow *)notification.object;
+ NSSize size = window.frame.size;
+ [self.view setFrameSize:size];
+ if (! self.window_cairo->resize(self.window_cairo, (uw) size.width,
+ size.height))
+ [NSApp stop:nil];
+ self.window_cairo->w = size.width;
+ self.window_cairo->h = size.height;
+}
+
+- (void)windowWillClose:(NSNotification *)notification {
+ [NSApp stop:nil];
+}
+
+@end
diff --git a/window/cairo/quartz/window_cairo_quartz_view.h b/window/cairo/quartz/window_cairo_quartz_view.h
new file mode 100644
index 0000000..6b7ceef
--- /dev/null
+++ b/window/cairo/quartz/window_cairo_quartz_view.h
@@ -0,0 +1,33 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_QUARTZ_VIEW_H
+#define LIBKC3_WINDOW_CAIRO_QUARTZ_VIEW_H
+
+#import <Cocoa/Cocoa.h>
+#import "../window_cairo.h"
+
+@interface WindowCairoQuartzView : NSView
+
+@property (nonatomic, assign) s_window_cairo *window_cairo;
+
+- (BOOL)acceptsFirstResponder;
+
+- (void) drawRect:(NSRect)dirtyRect;
+
+- (instancetype)initWithWindowCairo:(s_window_cairo *) window_cairo;
+
+- (void)keyDown:(NSEvent *)event;
+
+@end
+
+#endif /* LIBKC3_WINDOW_CAIRO_QUARTZ_VIEW_H */
diff --git a/window/cairo/quartz/window_cairo_quartz_view.m b/window/cairo/quartz/window_cairo_quartz_view.m
new file mode 100644
index 0000000..97d20ba
--- /dev/null
+++ b/window/cairo/quartz/window_cairo_quartz_view.m
@@ -0,0 +1,96 @@
+/* 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.
+ */
+#import <Foundation/Foundation.h>
+#import <cairo/cairo-quartz.h>
+#import <xkbcommon/xkbcommon.h>
+#import "quartz_to_xkbcommon.h"
+#import "window_cairo_quartz_view.h"
+
+@implementation WindowCairoQuartzView
+
+- (instancetype) initWithWindowCairo:(s_window_cairo *) window_cairo {
+ NSRect frame = NSMakeRect(window_cairo->x, window_cairo->y, window_cairo->w, window_cairo->h);
+ self = [super initWithFrame:frame];
+ if (self) {
+ self.window_cairo = window_cairo;
+ }
+ return self;
+}
+
+- (BOOL)acceptsFirstResponder {
+ return YES;
+}
+
+- (void) drawRect:(NSRect)dirtyRect {
+ [super drawRect:dirtyRect];
+ struct CGContext *cg_context = [[NSGraphicsContext currentContext]
+ CGContext];
+ CGContextTranslateCTM(cg_context, 0.0, self.bounds.size.height);
+ CGContextScaleCTM(cg_context, 1.0, -1.0);
+ cairo_surface_t *surface =
+ cairo_quartz_surface_create_for_cg_context(cg_context,
+ self.bounds.size.width,
+ self.bounds.size.height);
+ cairo_t *cr = cairo_create(surface);
+ self.window_cairo->cr = cr;
+ if (! self.window_cairo->render(self.window_cairo)) {
+ [self.window close];
+ [self.window release];
+ [[NSApplication sharedApplication] stop:nil];
+ }
+ cairo_surface_flush(surface);
+ cairo_destroy(cr);
+ cairo_surface_destroy(surface);
+}
+
+- (void)keyDown:(NSEvent *)event {
+ NSString *characters = [event characters];
+ unichar character = [characters characterAtIndex:0];
+ u32 keysym = quartz_to_xkbcommon(character);
+ if (! self.window_cairo->key(self.window_cairo, keysym)) {
+ [self.window close];
+ [self.window release];
+ [[NSApplication sharedApplication] stop:nil];
+ }
+}
+
+- (void)mouseDown:(NSEvent *)event {
+ NSPoint p = [event locationInWindow];
+ if (! self.window_cairo->button(self.window_cairo, 0, p.x, p.y)) {
+ [self.window close];
+ [self.window release];
+ [[NSApplication sharedApplication] stop:nil];
+ }
+}
+
+- (void)mouseMoved:(NSEvent *)event {
+ NSPoint p = [event locationInWindow];
+ p.y = self.window_cairo->h - p.y;
+ if (! self.window_cairo->motion(self.window_cairo, p.x, p.y)) {
+ [self.window close];
+ [self.window release];
+ [[NSApplication sharedApplication] stop:nil];
+ }
+}
+
+- (void)rightMouseDown:(NSEvent *)event {
+ NSPoint p = [event locationInWindow];
+ if (! self.window_cairo->button(self.window_cairo, 2, p.x, p.y)) {
+ [self.window close];
+ [self.window release];
+ [[NSApplication sharedApplication] stop:nil];
+ }
+}
+
+@end
+
diff --git a/window/cairo/quartz/window_cairo_quartz_view_controller.h b/window/cairo/quartz/window_cairo_quartz_view_controller.h
new file mode 100644
index 0000000..20b69db
--- /dev/null
+++ b/window/cairo/quartz/window_cairo_quartz_view_controller.h
@@ -0,0 +1,27 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_QUARTZ_VIEW_CONTROLLER_H
+#define LIBKC3_WINDOW_CAIRO_QUARTZ_VIEW_CONTROLLER_H
+
+#import <Cocoa/Cocoa.h>
+#import "window_cairo_quartz_view.h"
+
+@interface WindowCairoQuartzViewController : NSViewController
+
+@property (strong) WindowCairoQuartzView *cairo_view;
+
+- (instancetype) initWithCairoView:(WindowCairoQuartzView *)cairo_view;
+
+@end
+
+#endif /* LIBKC3_WINDOW_CAIRO_QUARTZ_VIEW_CONTROLLER_H */
diff --git a/window/cairo/quartz/window_cairo_quartz_view_controller.m b/window/cairo/quartz/window_cairo_quartz_view_controller.m
new file mode 100644
index 0000000..26c8358
--- /dev/null
+++ b/window/cairo/quartz/window_cairo_quartz_view_controller.m
@@ -0,0 +1,36 @@
+/* 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.
+ */
+#import <Cocoa/Cocoa.h>
+#import "window_cairo_quartz_view_controller.h"
+
+@implementation WindowCairoQuartzViewController
+
+- (instancetype) initWithCairoView:(WindowCairoQuartzView *)cairo_view {
+ self = [super init];
+ if (self) {
+ self.cairo_view = cairo_view;
+ }
+ return self;
+}
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+ [self.view addSubview:self.cairo_view];
+}
+
+- (void)viewDidAppear {
+ [super viewDidAppear];
+ [self.view.window makeFirstResponder:self.cairo_view];
+}
+
+@end
diff --git a/window/cairo/quartz/xkbquartz.h b/window/cairo/quartz/xkbquartz.h
new file mode 100644
index 0000000..9b2f1a6
--- /dev/null
+++ b/window/cairo/quartz/xkbquartz.h
@@ -0,0 +1,18 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_QUARTZ_H
+#define LIBKC3_WINDOW_CAIRO_QUARTZ_H
+
+
+
+#endif /* LIBKC3_WINDOW_CAIRO_XCB_H */
diff --git a/window/cairo/sources.mk b/window/cairo/sources.mk
new file mode 100644
index 0000000..cd231cc
--- /dev/null
+++ b/window/cairo/sources.mk
@@ -0,0 +1,14 @@
+# sources.mk generated by update_sources
+HEADERS = \
+ "cairo_font.h" \
+ "cairo_sprite.h" \
+ "cairo_text.h" \
+ "types.h" \
+ "window_cairo.h" \
+
+SOURCES = \
+ "cairo_font.c" \
+ "cairo_sprite.c" \
+ "cairo_text.c" \
+ "window_cairo.c" \
+
diff --git a/window/cairo/sources.sh b/window/cairo/sources.sh
new file mode 100644
index 0000000..7fcb3b5
--- /dev/null
+++ b/window/cairo/sources.sh
@@ -0,0 +1,3 @@
+# sources.sh generated by update_sources
+HEADERS='cairo_font.h cairo_sprite.h cairo_text.h types.h window_cairo.h '
+SOURCES='cairo_font.c cairo_sprite.c cairo_text.c window_cairo.c '
diff --git a/window/cairo/types.h b/window/cairo/types.h
new file mode 100644
index 0000000..4bd73ac
--- /dev/null
+++ b/window/cairo/types.h
@@ -0,0 +1,115 @@
+/* kc3
+ * Copyright 2022,2023,2024 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.
+ */
+/** @file types.h
+ * @brief Module C3.Window.Cairo
+ *
+ * Struct for all GUI window Cairo graphics operations.
+ */
+#ifndef LIBKC3_WINDOW_CAIRO_TYPES_H
+#define LIBKC3_WINDOW_CAIRO_TYPES_H
+
+#include <cairo.h>
+#include <cairo-ft.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include <png.h>
+#include <libkc3/types.h>
+#include "../types.h"
+
+typedef struct cairo_font s_cairo_font;
+typedef struct cairo_sprite s_cairo_sprite;
+typedef struct rgb s_rgb;
+typedef struct rgba s_rgba;
+typedef struct window_cairo s_window_cairo;
+
+/* return false to break event loop */
+typedef bool (*f_window_cairo_button) (s_window_cairo *window,
+ u8 button, sw x, sw y);
+
+/* return false to break event loop */
+typedef bool (*f_window_cairo_key) (s_window_cairo *window, uw keysym);
+
+/* return false to break event loop */
+typedef bool (*f_window_cairo_load) (s_window_cairo *window);
+
+/* return false to break event loop */
+typedef bool (*f_window_cairo_motion) (s_window_cairo *window, sw x,
+ sw y);
+
+/* return false to break event loop */
+typedef bool (*f_window_cairo_render) (s_window_cairo *window);
+
+/* return false to break event loop */
+typedef bool (*f_window_cairo_resize) (s_window_cairo *window,
+ uw w, uw h);
+
+typedef void (*f_window_cairo_unload) (s_window_cairo *window);
+
+struct cairo_font {
+ cairo_font_face_t *cairo_font_face;
+ FT_Face ft_face;
+ s_str path;
+ s_str real_path;
+};
+
+struct cairo_sprite {
+ s_str path;
+ s_str real_path;
+ uw total_w;
+ uw total_h;
+ uw dim_x;
+ uw dim_y;
+ uw frame_count;
+ uw w;
+ uw h;
+ //ILuint *il_image;
+ cairo_surface_t **surface;
+};
+
+struct rgb {
+ double r;
+ double g;
+ double b;
+};
+
+struct rgba {
+ double r;
+ double g;
+ double b;
+ double a;
+};
+
+/* Subtype of s_window. See libkc3/window/types.h */
+struct window_cairo {
+ sw x;
+ sw y;
+ uw w;
+ uw h;
+ bool fullscreen;
+ f_window_cairo_button button;
+ f_window_cairo_key key;
+ f_window_cairo_load load;
+ f_window_cairo_motion motion;
+ f_window_cairo_render render;
+ cairo_t *cr;
+ f_window_cairo_resize resize;
+ s_sequence *seq;
+ s_sequence *sequence;
+ uw sequence_count;
+ uw sequence_pos;
+ s_tag tag; // TODO: move sequence to tag
+ const char *title;
+ f_window_cairo_unload unload;
+};
+
+#endif /* LIBKC3_WINDOW_CAIRO_TYPES_H */
diff --git a/window/cairo/update_sources b/window/cairo/update_sources
new file mode 100755
index 0000000..7b6ba22
--- /dev/null
+++ b/window/cairo/update_sources
@@ -0,0 +1,33 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+. ../../config.subr
+
+echo "$PWD/update_sources"
+
+echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
+echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
+
+HEADERS="$(ls *.h | grep -v '^config.h$')"
+sources HEADERS "$HEADERS"
+
+SOURCES="$(ls *.c)"
+sources SOURCES "$SOURCES"
+
+update_sources_mk
+update_sources_sh
+
+( cd demo && ./update_sources; )
+( cd quartz && ./update_sources; )
+( cd win32 && ./update_sources; )
+( cd xcb && ./update_sources; )
diff --git a/window/cairo/win32/Makefile b/window/cairo/win32/Makefile
new file mode 100644
index 0000000..2d8037a
--- /dev/null
+++ b/window/cairo/win32/Makefile
@@ -0,0 +1,92 @@
+## kc3
+## Copyright 2022-2024 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.
+
+CLEANFILES = *.a *.gcno *.la .libs *.lo *.o
+
+CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
+
+CLEANFILES += ${CLEANFILES_COV}
+
+DISTCLEANFILES = ${CLEANFILES} config.h config.mk
+
+build:
+ ${MAKE} ${LIB}
+ ${MAKE} -C demo build
+
+all:
+ ${MAKE} build
+ if ${HAVE_GCOV}; then ${MAKE} cov; fi
+ ${MAKE} debug
+ if ${HAVE_ASAN}; then ${MAKE} asan; fi
+
+asan:
+ ${MAKE} ${LIB_ASAN}
+ ${MAKE} -C demo asan
+
+clean:
+ rm -rf ${CLEANFILES}
+ ${MAKE} -C demo clean
+
+clean_cov:
+ rm -rf ${CLEANFILES_COV}
+ ${MAKE} -C demo clean_cov
+
+cov:
+ ${MAKE} ${LIB_COV}
+ ${MAKE} -C demo cov
+
+debug:
+ ${MAKE} ${LIB_DEBUG}
+ ${MAKE} -C demo debug
+
+demo: build
+ ${MAKE} -C demo demo
+
+demo_asan: asan
+ ${MAKE} -C demo demo_asan
+
+demo_cov: cov
+ ${MAKE} -C demo demo_cov
+
+demo_debug: debug
+ ${MAKE} -C demo demo_debug
+
+distclean:
+ rm -rf ${DISTCLEANFILES}
+ ${MAKE} -C demo distclean
+
+gdb_demo: debug
+ ${MAKE} -C demo gdb_demo
+
+test: build
+ ${MAKE} -C demo test
+
+update_sources:
+ ./update_sources
+
+.PHONY: \
+ all \
+ asan \
+ build \
+ clean \
+ cov \
+ debug \
+ demo \
+ distclean \
+ gdb_demo \
+ gen \
+ install \
+ test \
+ update_sources
+
+include config.mk
+include sources.mk
diff --git a/window/cairo/win32/configure b/window/cairo/win32/configure
new file mode 100644
index 0000000..885d1d4
--- /dev/null
+++ b/window/cairo/win32/configure
@@ -0,0 +1,149 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+set -e
+
+export SRC_TOP="$(dirname "$PWD")"
+
+. ../../../../config.subr
+
+LIB=libkc3_window_cairo_win32.la
+LIB_ASAN=libkc3_window_cairo_win32_asan.la
+LIB_COV=libkc3_window_cairo_win32_cov.la
+LIB_DEBUG=libkc3_window_cairo_win32_debug.la
+
+echo "LIB = $LIB" >> ${CONFIG_MK}
+echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
+echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
+echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
+
+#LIBKC3=../../../libkc3.la
+#LIBKC3_ASAN=../../../libkc3_asan.la
+#LIBKC3_COV=../../../libkc3_cov.la
+#LIBKC3_DEBUG=../../../libkc3_debug.la
+
+. ./sources.sh
+
+OBJECTS="$(c2ext .main.lo "$SOURCES")"
+echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
+OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
+OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
+OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
+
+# Common config for all targets
+CPPFLAGS="-I../../../../libffi/include -I../../../.. $CPPFLAGS"
+CFLAGS="$CFLAGS -W -Wall -Werror -std=c99 -pedantic"
+LDFLAGS="--shared $LDFLAGS"
+LIBS="$LIBS -rpath ${PREFIX}/lib"
+config_asan
+config_gnu
+config_i386
+pkg_config xkbcommon
+pkg_config cairo
+pkg_config cairo-win32
+pkg_config libbsd-overlay
+pkg_config libmd
+config_define PREFIX "\"${PREFIX}\""
+update_config_h
+LIBS="$LIBS -lxkbcommon"
+
+# Address Sanitizer config
+CFLAGS_ASAN="$CFLAGS -O1 -fsanitize=address -fno-omit-frame-pointer -g"
+LDFLAGS_ASAN="$LDFLAGS"
+LIBS_LOCAL_ASAN="../libkc3_window_cairo_asan.la"
+LIBS_ASAN="$LIBS_LOCAL_ASAN $LIBS"
+
+# Coverage config
+CFLAGS_COV="$CFLAGS -ftest-coverage -fprofile-arcs -fprofile-generate"
+LDFLAGS_COV="$LDFLAGS --coverage"
+LIBS_LOCAL_COV="../libkc3_window_cairo_cov.la"
+LIBS_COV="$LIBS_LOCAL_COV $LIBS"
+
+# Debug config
+CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
+LDFLAGS_DEBUG="$LDFLAGS"
+LIBS_LOCAL_DEBUG="../libkc3_window_cairo_debug.la"
+LIBS_DEBUG="$LIBS_LOCAL_DEBUG $LIBS"
+
+# Main config
+DEFAULT_CFLAGS="-O2 -pipe"
+if [ "x$ENV_CFLAGS" = "x" ]; then
+ CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
+fi
+CFLAGS="$CFLAGS -DNDEBUG"
+LIBS_LOCAL="../libkc3_window_cairo.la"
+LIBS="$LIBS_LOCAL $LIBS"
+
+echo "LIB = $LIB" >> ${CONFIG_MK}
+echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
+echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
+echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
+echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
+echo "LIBS = $LIBS" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
+echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
+echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
+echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
+echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
+echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "$LIB: $LIBS_LOCAL $OBJECTS" >> ${CONFIG_MK}
+echo " ${LIBTOOL} --tag=CC --mode=link \${CC} -shared \${LDFLAGS} ${OBJECTS} \${LIBS} -rpath ${LIBDIR} -o ${LIB}" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "$LIB_ASAN: $LIBS_LOCAL_ASAN $OBJECTS_ASAN" >> ${CONFIG_MK}
+echo " ${LIBTOOL} --tag=CC --mode=link \${CC} -shared \${LDFLAGS_ASAN} ${OBJECTS_ASAN} \${LIBS_ASAN} -rpath ${LIBDIR} -o ${LIB_ASAN}" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "$LIB_COV: $LIBS_LOCAL_COV $OBJECTS_COV" >> ${CONFIG_MK}
+echo " ${LIBTOOL} --tag=CC --mode=link \${CC} -shared \${LDFLAGS_COV} ${OBJECTS_COV} \${LIBS_COV} -rpath ${LIBDIR} -o ${LIB_COV}" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "$LIB_DEBUG: $LIBS_LOCAL_DEBUG $OBJECTS_DEBUG" >> ${CONFIG_MK}
+echo " ${LIBTOOL} --tag=CC --mode=link \${CC} -shared \${LDFLAGS_DEBUG} ${OBJECTS_DEBUG} \${LIBS_DEBUG} -rpath ${LIBDIR} -o ${LIB_DEBUG}" >> ${CONFIG_MK}
+
+for SRC in $SOURCES; do
+ echo >> ${CONFIG_MK}
+ SRC_LO="$(c2ext .main.lo "$SRC")"
+ c_ext_rule .main.lo "$SRC" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS} -c $SRC -o $SRC_LO" >> ${CONFIG_MK}
+
+ echo >> ${CONFIG_MK}
+ SRC_ASAN_LO="$(c2ext .asan.lo "$SRC")"
+ c_ext_rule .asan.lo "$SRC" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_ASAN} -c $SRC -o $SRC_ASAN_LO" >> ${CONFIG_MK}
+
+ echo >> ${CONFIG_MK}
+ SRC_COV_LO="$(c2ext .cov.lo "$SRC")"
+ c_ext_rule .cov.lo "$SRC" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_COV} -c $SRC -o $SRC_COV_LO" >> ${CONFIG_MK}
+
+ echo >> ${CONFIG_MK}
+ SRC_DEBUG_LO="$(c2ext .debug.lo "$SRC")"
+ c_ext_rule .debug.lo "$SRC" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_DEBUG} -c $SRC -o $SRC_DEBUG_LO" >> ${CONFIG_MK}
+done
+
+update_config_mk
+env_reset
+( cd demo && ./configure; )
diff --git a/window/cairo/win32/demo/Makefile b/window/cairo/win32/demo/Makefile
new file mode 100644
index 0000000..89a2497
--- /dev/null
+++ b/window/cairo/win32/demo/Makefile
@@ -0,0 +1,78 @@
+## kc3
+## Copyright 2022-2024 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 config.mk
+include sources.mk
+
+CLEANFILES = *.a ${PROG} ${PROG_ASAN} ${PROG_COV} ${PROG_DEBUG} *.css \
+ *.gcno *.html *.o .libs *.lo
+
+CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
+CLEANFILES += ${CLEANFILES_COV}
+
+DISTCLEANFILES = ${CLEANFILES} config.mk
+
+build: ${PROG}
+
+all:
+ ${MAKE} build
+ if ${HAVE_GCOV}; then ${MAKE} cov; fi
+ ${MAKE} debug
+ if ${HAVE_ASAN}; then ${MAKE} asan; fi
+
+asan: ${PROG_ASAN}
+
+clean:
+ rm -rf ${CLEANFILES}
+
+clean_cov:
+ rm -rf ${CLEANFILES_COV}
+
+cov: ${PROG_COV}
+
+debug: ${PROG_DEBUG}
+
+demo: ${PROG}
+ time ./${PROG}
+
+demo_asan: ${PROG_ASAN}
+ time ./${PROG_ASAN}
+
+demo_cov: ${PROG_COV}
+ time ./${PROG_COV}
+
+demo_debug: ${PROG_DEBUG}
+ time ./${PROG_DEBUG}
+
+distclean:
+ rm -rf ${DISTCLEANFILES}
+
+gcovr:
+ gcovr --gcov-executable ${GCOV} --html-details ${PROG}.html
+
+gdb_demo: debug
+ if [ -f ${PROG_DEBUG}.core ]; then gdb .libs/${PROG_DEBUG} ${PROG_DEBUG}.core; else gdb .libs/${PROG_DEBUG}; fi
+
+install:
+ install -m 755 -d ${prefix}/bin
+ install -m 755 ${PROG} ${prefix}/bin/${PROG}
+
+.PHONY: \
+ all \
+ asan \
+ clean \
+ clean_cov \
+ cov \
+ debug \
+ demo \
+ distclean \
+ gdb_demo
diff --git a/window/cairo/win32/demo/configure b/window/cairo/win32/demo/configure
new file mode 100644
index 0000000..11b1cb7
--- /dev/null
+++ b/window/cairo/win32/demo/configure
@@ -0,0 +1,144 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+set -e
+
+export SRC_TOP="$(dirname "$PWD")"
+
+. ../../../../../config.subr
+
+PROG=c3_window_cairo_win32_demo
+PROG_ASAN=c3_window_cairo_win32_demo_asan
+PROG_COV=c3_window_cairo_win32_demo_cov
+PROG_DEBUG=c3_window_cairo_win32_demo_debug
+
+echo "PROG = $PROG" >> ${CONFIG_MK}
+echo "PROG_ASAN = $PROG_ASAN" >> ${CONFIG_MK}
+echo "PROG_COV = $PROG_COV" >> ${CONFIG_MK}
+echo "PROG_DEBUG = $PROG_DEBUG" >> ${CONFIG_MK}
+
+. ./sources.sh
+
+OBJECTS="$(c2ext .main.lo "$SOURCES")"
+echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
+
+OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
+echo "OBJECTS_ASAN = $OBJECTS_ASAN" >> ${CONFIG_MK}
+
+if $HAVE_GCOV; then
+ OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
+ echo "OBJECTS_COV = $OBJECTS_COV" >> ${CONFIG_MK}
+fi
+
+OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
+echo "OBJECTS_DEBUG = $OBJECTS_DEBUG" >> ${CONFIG_MK}
+
+# Common config for all targets
+CFLAGS="$CFLAGS -W -Wall -Werror -std=c99 -pedantic"
+CPPFLAGS="-I../../../../../libffi/include -I../../../../.. $CPPFLAGS"
+config_asan
+config_gnu
+config_i386
+pkg_config libbsd-overlay
+pkg_config cairo
+pkg_config cairo-win32
+LIBS="$LIBS"
+
+# Asan config
+CFLAGS_ASAN="$CFLAGS -fsanitize=address -O1 -fno-omit-frame-pointer -g"
+LDFLAGS_ASAN="$LDFLAGS"
+LOCAL_LIBS_ASAN="../../demo/libkc3_window_cairo_demo_asan.la ../libkc3_window_cairo_win32_asan.la"
+LIBS_ASAN="$LOCAL_LIBS_ASAN $LIBS"
+
+# Coverage config
+CFLAGS_COV="$CFLAGS -ftest-coverage -fprofile-arcs -fprofile-generate"
+LDFLAGS_COV="$LDFLAGS --coverage"
+LOCAL_LIBS_COV="../../demo/libkc3_window_cairo_demo_cov.la ../libkc3_window_cairo_win32_cov.la"
+LIBS_COV="$LOCAL_LIBS_COV $LIBS"
+
+# Debug config
+CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
+LDFLAGS_DEBUG="$LDFLAGS"
+LOCAL_LIBS_DEBUG="../../demo/libkc3_window_cairo_demo_debug.la ../libkc3_window_cairo_win32_debug.la"
+LIBS_DEBUG="$LOCAL_LIBS_DEBUG $LIBS"
+
+# Main config
+DEFAULT_CFLAGS="-O2 -pipe"
+if [ "x$ENV_CFLAGS" = "x" ]; then
+ CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
+fi
+CFLAGS="$CFLAGS -DNDEBUG"
+LOCAL_LIBS="../../demo/libkc3_window_cairo_demo.la ../libkc3_window_cairo_win32.la"
+LIBS="$LOCAL_LIBS $LIBS"
+
+echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
+echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
+echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
+echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
+echo "LIBS = $LIBS" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
+echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
+echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "$PROG: $LOCAL_LIBS $OBJECTS" >> ${CONFIG_MK}
+echo " ${LIBTOOL} --tag=CC --mode=link \${CC} \${CFLAGS} \${LDFLAGS} ${OBJECTS} ${LIBS} -o $PROG" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "$PROG_ASAN: $LOCAL_LIBS_ASAN $OBJECTS_ASAN" >> ${CONFIG_MK}
+echo " ${LIBTOOL} --tag=CC --mode=link \${CC} \${CFLAGS_ASAN} \${LDFLAGS_ASAN} ${OBJECTS_ASAN} ${LIBS_ASAN} -o $PROG_ASAN" >> ${CONFIG_MK}
+
+if $HAVE_GCOV; then
+ echo >> ${CONFIG_MK}
+ echo "$PROG_COV: $LOCAL_LIBS_COV $OBJECTS_COV" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=link \${CC} \${CFLAGS_COV} \${LDFLAGS_COV} ${OBJECTS_COV} ${LIBS_COV} -o $PROG_COV" >> ${CONFIG_MK}
+fi
+
+echo >> ${CONFIG_MK}
+echo "$PROG_DEBUG: $LOCAL_LIBS_DEBUG $OBJECTS_DEBUG" >> ${CONFIG_MK}
+echo " ${LIBTOOL} --tag=CC --mode=link \${CC} \${CFLAGS_DEBUG} \${LDFLAGS_DEBUG} ${OBJECTS_DEBUG} ${LIBS_DEBUG} -o $PROG_DEBUG" >> ${CONFIG_MK}
+
+for SRC in $SOURCES; do
+ echo >> ${CONFIG_MK}
+ SRC_LO="$(c2ext .main.lo "$SRC")"
+ c_ext_rule .main.lo "$SRC" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS} -c $SRC -o $SRC_LO" >> ${CONFIG_MK}
+
+ echo >> ${CONFIG_MK}
+ SRC_ASAN_LO="$(c2ext .asan.lo "$SRC")"
+ c_ext_rule .asan.lo "$SRC" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_ASAN} -c $SRC -o $SRC_ASAN_LO" >> ${CONFIG_MK}
+
+ if $HAVE_GCOV; then
+ echo >> ${CONFIG_MK}
+ SRC_COV_LO="$(c2ext .cov.lo "$SRC")"
+ c_ext_rule .cov.lo "$SRC" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_COV} -c $SRC -o $SRC_COV_LO" >> ${CONFIG_MK}
+ fi
+
+ echo >> ${CONFIG_MK}
+ SRC_DEBUG_LO="$(c2ext .debug.lo "$SRC")"
+ c_ext_rule .debug.lo "$SRC" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_DEBUG} -c $SRC -o $SRC_DEBUG_LO" >> ${CONFIG_MK}
+done
+
+update_config_mk
diff --git a/window/cairo/win32/demo/sources.mk b/window/cairo/win32/demo/sources.mk
new file mode 100644
index 0000000..1dc7825
--- /dev/null
+++ b/window/cairo/win32/demo/sources.mk
@@ -0,0 +1,7 @@
+# sources.mk generated by update_sources
+HEADERS = \
+ "" \
+
+SOURCES = \
+ "window_cairo_win32_demo.c" \
+
diff --git a/window/cairo/win32/demo/sources.sh b/window/cairo/win32/demo/sources.sh
new file mode 100644
index 0000000..9df3998
--- /dev/null
+++ b/window/cairo/win32/demo/sources.sh
@@ -0,0 +1,3 @@
+# sources.sh generated by update_sources
+HEADERS=' '
+SOURCES='window_cairo_win32_demo.c '
diff --git a/window/cairo/win32/demo/update_sources b/window/cairo/win32/demo/update_sources
new file mode 100755
index 0000000..98e6491
--- /dev/null
+++ b/window/cairo/win32/demo/update_sources
@@ -0,0 +1,29 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+. ../../../../config.subr
+
+echo "$PWD/update_sources"
+
+echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
+echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
+
+#HEADERS="$(ls *.h | grep -v '^config.h$')"
+HEADERS=
+sources HEADERS "$HEADERS"
+
+SOURCES="$(ls *.c)"
+sources SOURCES "$SOURCES"
+
+update_sources_mk
+update_sources_sh
diff --git a/window/cairo/win32/demo/window_cairo_win32_demo.c b/window/cairo/win32/demo/window_cairo_win32_demo.c
new file mode 100644
index 0000000..0443ebd
--- /dev/null
+++ b/window/cairo/win32/demo/window_cairo_win32_demo.c
@@ -0,0 +1,40 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <stdio.h>
+#include <stdlib.h>
+#include <cairo/cairo.h>
+#include <libkc3/kc3.h>
+#include "../../../window.h"
+#include "../../demo/window_cairo_demo.h"
+#include "../window_cairo_win32.h"
+
+int main (int argc, char **argv)
+{
+ s_window_cairo window;
+ if (! c3_init(NULL, argc, argv))
+ return 1;
+ c3_window_cairo_init();
+ window_cairo_init(&window, 0, 0, 800, 600,
+ "C3.Window.Cairo.Win32 demo",
+ WINDOW_CAIRO_DEMO_SEQUENCE_COUNT);
+ window.button = window_cairo_demo_button;
+ window.key = window_cairo_demo_key;
+ window.load = window_cairo_demo_load;
+ window.render = window_cairo_demo_render;
+ window.resize = window_cairo_demo_resize;
+ if (! window_cairo_win32_run(&window))
+ return g_c3_exit_code;
+ c3_window_cairo_clean();
+ c3_clean(NULL);
+ return 0;
+}
diff --git a/window/cairo/win32/sources.mk b/window/cairo/win32/sources.mk
new file mode 100644
index 0000000..9dd7f59
--- /dev/null
+++ b/window/cairo/win32/sources.mk
@@ -0,0 +1,9 @@
+# sources.mk generated by update_sources
+HEADERS = \
+ "vk_to_xkbcommon.h" \
+ "window_cairo_win32.h" \
+
+SOURCES = \
+ "vk_to_xkbcommon.c" \
+ "window_cairo_win32.c" \
+
diff --git a/window/cairo/win32/sources.sh b/window/cairo/win32/sources.sh
new file mode 100644
index 0000000..7492652
--- /dev/null
+++ b/window/cairo/win32/sources.sh
@@ -0,0 +1,3 @@
+# sources.sh generated by update_sources
+HEADERS='vk_to_xkbcommon.h window_cairo_win32.h '
+SOURCES='vk_to_xkbcommon.c window_cairo_win32.c '
diff --git a/window/cairo/win32/update_sources b/window/cairo/win32/update_sources
new file mode 100755
index 0000000..abe35fb
--- /dev/null
+++ b/window/cairo/win32/update_sources
@@ -0,0 +1,30 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+. ../../../config.subr
+
+echo "$PWD/update_sources"
+
+echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
+echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
+
+HEADERS="$(ls *.h | grep -v '^config.h$')"
+sources HEADERS "$HEADERS"
+
+SOURCES="$(ls *.c)"
+sources SOURCES "$SOURCES"
+
+update_sources_mk
+update_sources_sh
+
+( cd demo && ./update_sources; )
diff --git a/window/cairo/win32/vk_to_xkbcommon.c b/window/cairo/win32/vk_to_xkbcommon.c
new file mode 100644
index 0000000..5a7df28
--- /dev/null
+++ b/window/cairo/win32/vk_to_xkbcommon.c
@@ -0,0 +1,99 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <windows.h>
+#include <xkbcommon/xkbcommon.h>
+#include <libkc3/types.h>
+
+u32 vk_to_xkbcommon (u32 vk_key)
+{
+ switch (vk_key) {
+ case VK_ESCAPE: return XKB_KEY_Escape;
+ case VK_F1: return XKB_KEY_F1;
+ case VK_F2: return XKB_KEY_F2;
+ case VK_F3: return XKB_KEY_F3;
+ case VK_F4: return XKB_KEY_F4;
+ case VK_F5: return XKB_KEY_F5;
+ case VK_F6: return XKB_KEY_F6;
+ case VK_F7: return XKB_KEY_F7;
+ case VK_F8: return XKB_KEY_F8;
+ case VK_F9: return XKB_KEY_F9;
+ case VK_F10: return XKB_KEY_F10;
+ case VK_F11: return XKB_KEY_F11;
+ case VK_F12: return XKB_KEY_F12;
+ /*
+ case : return XKB_KEY_grave;
+ */
+ case 0x31: return XKB_KEY_1;
+ case 0x32: return XKB_KEY_2;
+ case 0x33: return XKB_KEY_3;
+ case 0x34: return XKB_KEY_4;
+ case 0x35: return XKB_KEY_5;
+ case 0x36: return XKB_KEY_6;
+ case 0x37: return XKB_KEY_7;
+ case 0x38: return XKB_KEY_8;
+ case 0x39: return XKB_KEY_9;
+ case 0x30: return XKB_KEY_0;
+ /*
+ case 45: return XKB_KEY_minus;
+ case 61: return XKB_KEY_equal;
+ */
+ case VK_BACK: return XKB_KEY_BackSpace;
+ case VK_TAB: return XKB_KEY_Tab;
+ case 0x41: return XKB_KEY_a;
+ case 0x42: return XKB_KEY_b;
+ case 0x43: return XKB_KEY_c;
+ case 0x44: return XKB_KEY_d;
+ case 0x45: return XKB_KEY_e;
+ case 0x46: return XKB_KEY_f;
+ case 0x47: return XKB_KEY_g;
+ case 0x48: return XKB_KEY_h;
+ case 0x49: return XKB_KEY_i;
+ case 0x4A: return XKB_KEY_j;
+ case 0x4B: return XKB_KEY_k;
+ case 0x4C: return XKB_KEY_l;
+ case 0x4D: return XKB_KEY_m;
+ case 0x4E: return XKB_KEY_n;
+ case 0x4F: return XKB_KEY_o;
+ case 0x50: return XKB_KEY_p;
+ case 0x51: return XKB_KEY_q;
+ case 0x52: return XKB_KEY_r;
+ case 0x53: return XKB_KEY_s;
+ case 0x54: return XKB_KEY_t;
+ case 0x55: return XKB_KEY_u;
+ case 0x56: return XKB_KEY_v;
+ case 0x57: return XKB_KEY_w;
+ case 0x58: return XKB_KEY_x;
+ case 0x59: return XKB_KEY_y;
+ case 0x5A: return XKB_KEY_z;
+ /*
+ case 91: return XKB_KEY_bracketleft;
+ case 93: return XKB_KEY_bracketright;
+ case 92: return XKB_KEY_backslash;
+ case 59: return XKB_KEY_semicolon;
+ case 39: return XKB_KEY_apostrophe;
+ */
+ case VK_RETURN: return XKB_KEY_Return;
+ /*
+ case 44: return XKB_KEY_comma;
+ case 46: return XKB_KEY_period;
+ case 47: return XKB_KEY_slash;
+ */
+ case VK_SPACE: return XKB_KEY_space;
+ case VK_UP: return XKB_KEY_Up;
+ case VK_DOWN: return XKB_KEY_Down;
+ case VK_LEFT: return XKB_KEY_Left;
+ case VK_RIGHT: return XKB_KEY_Right;
+ default: break;
+ }
+ return XKB_KEY_NoSymbol;
+}
diff --git a/window/cairo/win32/vk_to_xkbcommon.h b/window/cairo/win32/vk_to_xkbcommon.h
new file mode 100644
index 0000000..2a798b3
--- /dev/null
+++ b/window/cairo/win32/vk_to_xkbcommon.h
@@ -0,0 +1,20 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_WIN32_VK_TO_XKBCOMMON_H
+#define LIBKC3_WINDOW_CAIRO_WIN32_VK_TO_XKBCOMMON_H
+
+#include <libkc3/types.h>
+
+u32 vk_to_xkbcommon (u32 vk_key);
+
+#endif /* LIBKC3_WINDOW_CAIRO_WIN32_VK_TO_XKBCOMMON_H */
diff --git a/window/cairo/win32/window_cairo_win32.c b/window/cairo/win32/window_cairo_win32.c
new file mode 100644
index 0000000..1c7827c
--- /dev/null
+++ b/window/cairo/win32/window_cairo_win32.c
@@ -0,0 +1,147 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <stdio.h>
+#include <stdlib.h>
+#include <xkbcommon/xkbcommon.h>
+#include <windows.h>
+#include <cairo.h>
+#include <cairo-win32.h>
+#include <libkc3/kc3.h>
+#include "vk_to_xkbcommon.h"
+#include "window_cairo_win32.h"
+
+bool window_cairo_run (s_window_cairo *window)
+{
+ return window_cairo_win32_run(window);
+}
+
+LRESULT CALLBACK window_cairo_win32_proc (HWND hwnd, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+ HBITMAP buffer_hbitmap;
+ HDC buffer_hdc;
+ cairo_t *cr;
+ HDC hdc;
+ u32 keysym;
+ PAINTSTRUCT ps;
+ cairo_surface_t *surface;
+ u32 vk;
+ s_window_cairo *window;
+ HDC window_hdc;
+ window = (s_window_cairo *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ switch (message) {
+ case WM_DESTROY:
+ printf("WM_DESTROY\n");
+ PostQuitMessage(0);
+ break;
+ case WM_ERASEBKGND:
+ return 1;
+ case WM_KEYDOWN:
+ vk = (u32) wParam;
+ keysym = vk_to_xkbcommon(vk);
+ if (! window->key(window, keysym)) {
+ printf("window->key -> false\n");
+ PostQuitMessage(1);
+ }
+ break;
+ case WM_PAINT:
+ window_hdc = GetDC(hwnd);
+ buffer_hdc = CreateCompatibleDC(window_hdc);
+ buffer_hbitmap = CreateCompatibleBitmap(window_hdc, window->w,
+ window->h);
+ SelectObject(buffer_hdc, buffer_hbitmap);
+ surface = cairo_win32_surface_create(buffer_hdc);
+ cr = cairo_create(surface);
+ window->cr = cr;
+ if (! window->render(window)) {
+ printf("render -> false\n");
+ PostQuitMessage(1);
+ }
+ cairo_surface_flush(surface);
+ cairo_destroy(window->cr);
+ cairo_surface_destroy(surface);
+ hdc = BeginPaint(hwnd, &ps);
+ BitBlt(hdc, 0, 0, window->w, window->h, buffer_hdc, 0, 0, SRCCOPY);
+ EndPaint(hwnd, &ps);
+ DeleteObject(buffer_hbitmap);
+ DeleteDC(buffer_hdc);
+ DeleteDC(window_hdc);
+ DeleteDC(hdc);
+ break;
+ case WM_SIZE:
+ if (! window->resize(window, LOWORD(lParam), HIWORD(lParam)))
+ PostQuitMessage(1);
+ window->w = LOWORD(lParam);
+ window->h = HIWORD(lParam);
+ InvalidateRect(hwnd, NULL, TRUE);
+ break;
+ default:
+ return DefWindowProc(hwnd, message, wParam, lParam);
+ }
+ return 0;
+}
+
+bool window_cairo_win32_run (s_window_cairo *window)
+{
+ HWND hwnd;
+ MSG msg;
+ s_timespec sleep;
+ WNDCLASSEX wc;
+ wc.cbSize = sizeof(WNDCLASSEX);
+ wc.style = 0;
+ wc.lpfnWndProc = window_cairo_win32_proc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = "Libc3WindowCairoWin32";
+ wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
+ if (!RegisterClassEx(&wc)) {
+ MessageBox(NULL, "Window Registration Failed!", "Error!",
+ MB_ICONEXCLAMATION | MB_OK);
+ return 0;
+ }
+ hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,
+ "Libc3WindowCairoWin32",
+ window->title,
+ WS_OVERLAPPEDWINDOW,
+ window->x, window->y, window->w, window->h,
+ NULL, NULL, GetModuleHandle(NULL), NULL);
+ if (hwnd == NULL) {
+ MessageBox(NULL, "Window Creation Failed!", "Error!",
+ MB_ICONEXCLAMATION | MB_OK);
+ return 0;
+ }
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) window);
+ if (! window->load(window))
+ PostQuitMessage(1);
+ ShowWindow(hwnd, SW_SHOWDEFAULT);
+ UpdateWindow(hwnd);
+ while (true) {
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ if (msg.message == WM_QUIT)
+ goto quit;
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ sleep.tv_sec = 0;
+ sleep.tv_nsec = 1000000000 / 120;
+ nanosleep(&sleep, NULL);
+ InvalidateRect(hwnd, NULL, TRUE);
+ }
+ quit:
+ return msg.wParam ? false : true;
+}
diff --git a/window/cairo/win32/window_cairo_win32.h b/window/cairo/win32/window_cairo_win32.h
new file mode 100644
index 0000000..1df6e49
--- /dev/null
+++ b/window/cairo/win32/window_cairo_win32.h
@@ -0,0 +1,20 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_WIN32_H
+#define LIBKC3_WINDOW_CAIRO_WIN32_H
+
+#include "../window_cairo.h"
+
+bool window_cairo_win32_run (s_window_cairo *window);
+
+#endif /* LIBKC3_WINDOW_CAIRO_XCB_H */
diff --git a/window/cairo/window_cairo.c b/window/cairo/window_cairo.c
new file mode 100644
index 0000000..8632633
--- /dev/null
+++ b/window/cairo/window_cairo.c
@@ -0,0 +1,116 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <assert.h>
+#include <stdlib.h>
+#include <xkbcommon/xkbcommon.h>
+#include <libkc3/tag.h>
+#include "../window.h"
+#include "window_cairo.h"
+
+void kc3_window_cairo_clean (void)
+{
+}
+
+void kc3_window_cairo_init (void)
+{
+}
+
+void window_cairo_clean (s_window_cairo *window)
+{
+ window_clean((s_window *) window);
+}
+
+s_window_cairo * window_cairo_init (s_window_cairo *window,
+ sw x, sw y, uw w, uw h,
+ const char *title,
+ uw sequence_count)
+{
+ s_window_cairo tmp = {0};
+ assert(window);
+ title = title ? title : "KC3.Window.Cairo";
+ window_init((s_window *) &tmp, x, y, w, h, title, sequence_count);
+ tmp.button = window_cairo_button_default;
+ tmp.key = window_cairo_key_default;
+ tmp.load = window_cairo_load_default;
+ tmp.motion = window_cairo_motion_default;
+ tmp.render = window_cairo_render_default;
+ tmp.resize = window_cairo_resize_default;
+ *window = tmp;
+ return window;
+}
+
+bool window_cairo_button_default (s_window_cairo *window, u8 button,
+ sw x, sw y)
+{
+ assert(window);
+ (void) window;
+ (void) button;
+ (void) x;
+ (void) y;
+ printf("window_cairo_button_default: %d (%ld, %ld)\n",
+ (int) button, x, y);
+ return true;
+}
+
+bool window_cairo_key_default (s_window_cairo *window, uw keysym)
+{
+ char keysym_name[64];
+ assert(window);
+ (void) window;
+ xkb_keysym_get_name(keysym, keysym_name, sizeof(keysym_name));
+ printf("window_cairo_key_default: %lu %s\n", keysym, keysym_name);
+ return true;
+}
+
+bool window_cairo_load_default (s_window_cairo *window)
+{
+ assert(window);
+ (void) window;
+ printf("window_cairo_load_default\n");
+ return true;
+}
+
+bool window_cairo_motion_default (s_window_cairo *window, sw x, sw y)
+{
+ assert(window);
+ (void) window;
+ (void) x;
+ (void) y;
+ /*
+ printf("window_cairo_motion_default (%ld, %ld)\n", x, y);
+ */
+ return true;
+}
+
+bool window_cairo_render_default (s_window_cairo *window)
+{
+ cairo_t *cr;
+ assert(window);
+ cr = window->cr;
+ assert(cr);
+ cairo_set_source_rgb(cr, 1, 1, 1);
+ cairo_rectangle(cr, 0, 0, window->w, window->h);
+ cairo_fill(cr);
+ printf("window_cairo_render_default\n");
+ return true;
+}
+
+bool window_cairo_resize_default (s_window_cairo *window, uw w, uw h)
+{
+ assert(window);
+ (void) window;
+ (void) w;
+ (void) h;
+ printf("window_cairo_resize_default: %lu x %lu\n", w, h);
+ return true;
+}
diff --git a/window/cairo/window_cairo.h b/window/cairo/window_cairo.h
new file mode 100644
index 0000000..786a969
--- /dev/null
+++ b/window/cairo/window_cairo.h
@@ -0,0 +1,41 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_H
+#define LIBKC3_WINDOW_CAIRO_H
+
+#include "types.h"
+
+/* Library functions, call kc3_window_cairo_init at program start,
+ and kc3_window_cairo_clean at program end. */
+void kc3_window_cairo_clean (void);
+void kc3_window_cairo_init (void);
+
+/* Stack-allocation compatible functions, call window_cairo_clean
+ after use. */
+void window_cairo_clean (s_window_cairo *window);
+s_window_cairo * window_cairo_init (s_window_cairo *window,
+ sw x, sw y, uw w, uw h,
+ const char *title,
+ uw sequence_count);
+bool window_cairo_run (s_window_cairo *window);
+
+/* Callbacks. */
+bool window_cairo_button_default (s_window_cairo *window, u8 button,
+ sw x, sw y);
+bool window_cairo_key_default (s_window_cairo *window, uw keysym);
+bool window_cairo_load_default (s_window_cairo *window);
+bool window_cairo_motion_default (s_window_cairo *window, sw x, sw y);
+bool window_cairo_render_default (s_window_cairo *window);
+bool window_cairo_resize_default (s_window_cairo *window, uw w, uw h);
+
+#endif /* LIBKC3_WINDOW_CAIRO_H */
diff --git a/window/cairo/xcb/Makefile b/window/cairo/xcb/Makefile
new file mode 100644
index 0000000..140213f
--- /dev/null
+++ b/window/cairo/xcb/Makefile
@@ -0,0 +1,104 @@
+## kc3
+## Copyright 2022-2024 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.
+
+CLEANFILES = *.a *.gcno *.la .libs *.lo *.o
+
+CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
+
+CLEANFILES += ${CLEANFILES_COV}
+
+DISTCLEANFILES = ${CLEANFILES} config.h config.mk
+
+build:
+ ${MAKE} ${LIB}
+ ${MAKE} -C demo build
+
+all:
+ ${MAKE} build
+ if ${HAVE_GCOV}; then ${MAKE} cov; fi
+ ${MAKE} debug
+ if ${HAVE_ASAN}; then ${MAKE} asan; fi
+
+asan:
+ ${MAKE} ${LIB_ASAN}
+ ${MAKE} -C demo asan
+
+clean:
+ rm -rf ${CLEANFILES}
+ ${MAKE} -C demo clean
+
+clean_cov:
+ rm -rf ${CLEANFILES_COV}
+ ${MAKE} -C demo clean_cov
+
+cov:
+ ${MAKE} ${LIB_COV}
+ ${MAKE} -C demo cov
+
+debug:
+ ${MAKE} ${LIB_DEBUG}
+ ${MAKE} -C demo debug
+
+demo: build
+ ${MAKE} -C demo demo
+
+demo_asan: asan
+ ${MAKE} -C demo demo_asan
+
+demo_cov: cov
+ ${MAKE} -C demo demo_cov
+
+demo_debug: debug
+ ${MAKE} -C demo demo_debug
+
+distclean:
+ rm -rf ${DISTCLEANFILES}
+ ${MAKE} -C demo distclean
+
+gdb_demo: debug
+ ${MAKE} -C demo gdb_demo
+
+install:
+ ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0755 -d ${prefix}/include/libc3/window/cairo/xcb
+ ${LIBTOOL} --tag=CC --mode=install ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0644 ${HEADERS} ${prefix}/include/libc3/window/cairo/xcb
+ ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0755 -d ${prefix}/lib
+ ${LIBTOOL} --tag=CC --mode=install ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0644 ${LIB} ${prefix}/lib
+ ${LIBTOOL} --finish ${prefix}/lib
+ ${MAKE} -C demo install
+
+test: build
+ ${MAKE} -C demo test
+
+update_sources:
+ ./update_sources
+
+.PHONY: \
+ all \
+ asan \
+ build \
+ clean \
+ cov \
+ debug \
+ demo \
+ demo_asan \
+ demo_cov \
+ demo_debug \
+ distclean \
+ gdb_demo \
+ gen \
+ install \
+ lldb_demo \
+ test \
+ update_sources
+
+include config.mk
+include sources.mk
diff --git a/window/cairo/xcb/configure b/window/cairo/xcb/configure
new file mode 100755
index 0000000..8666872
--- /dev/null
+++ b/window/cairo/xcb/configure
@@ -0,0 +1,123 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+set -e
+
+echo "$PWD/configure"
+
+export SRC_TOP="$(dirname "$PWD")"
+
+CONFIG_H_PREFIX=LIBKC3_WINDOW_CAIRO_XCB_
+
+. ../../../config.subr
+
+LIB=libkc3_window_cairo_xcb.la
+LIB_ASAN=libkc3_window_cairo_xcb_asan.la
+LIB_COV=libkc3_window_cairo_xcb_cov.la
+LIB_DEBUG=libkc3_window_cairo_xcb_debug.la
+
+echo "LIB = $LIB" >> ${CONFIG_MK}
+echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
+echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
+echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
+
+. ./sources.sh
+
+OBJECTS="$(c2ext .main.lo "$SOURCES")"
+echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
+OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
+OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
+OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
+
+# Common config for all targets
+CPPFLAGS="$CPPFLAGS -I../../.."
+CFLAGS="$CFLAGS -W -Wall -Werror -std=c11 -pedantic -pipe"
+LDFLAGS="--shared ${LDFLAGS}"
+config_asan
+config_gnu
+config_i386
+pkg_config libbsd-overlay
+pkg_config libffi
+pkg_config libmd
+pkg_config xcb
+pkg_config xkbcommon
+pkg_config cairo
+pkg_config cairo-xcb
+config_define PREFIX "\"${PREFIX}\""
+update_config_h
+LIBS="$LIBS -lxkbcommon -lxkbcommon-x11"
+LIBS="$LIBS -rpath ${PREFIX}/lib"
+
+# Address Sanitizer config
+CPPFLAGS_ASAN="$CPPFLAGS"
+CFLAGS_ASAN="$CFLAGS -DDEBUG -O1 -g"
+CFLAGS_ASAN="$CFLAGS_ASAN -fsanitize=address -fno-omit-frame-pointer"
+LDFLAGS_ASAN="$LDFLAGS"
+LIBS_LOCAL_ASAN="../libkc3_window_cairo_asan.la"
+LIBS_ASAN="$LIBS_LOCAL_ASAN $LIBS"
+
+# Coverage config
+CPPFLAGS_COV="$CPPFLAGS"
+CFLAGS_COV="$CFLAGS -DDEBUG --coverage"
+LDFLAGS_COV="$LDFLAGS"
+LIBS_LOCAL_COV="../libkc3_window_cairo_cov.la"
+LIBS_COV="$LIBS_LOCAL_COV $LIBS"
+
+# Debug config
+CPPFLAGS_DEBUG="$CPPFLAGS"
+CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
+LDFLAGS_DEBUG="$LDFLAGS"
+LIBS_LOCAL_DEBUG="../libkc3_window_cairo_debug.la"
+LIBS_DEBUG="$LIBS_LOCAL_DEBUG $LIBS"
+
+# Main config
+DEFAULT_CFLAGS="-O2 -fPIC"
+if [ "x$ENV_CFLAGS" = "x" ]; then
+ CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
+fi
+CFLAGS="$CFLAGS -DNDEBUG"
+LIBS_LOCAL="../libkc3_window_cairo.la"
+LIBS="$LIBS_LOCAL $LIBS"
+
+echo "LIB = $LIB" >> ${CONFIG_MK}
+echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
+echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
+echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
+echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
+echo "LIBS = $LIBS" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
+echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
+echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
+echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
+echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
+echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
+
+update_build
+update_build_lib
+
+build_lo
+build_lib
+
+update_config_mk
+env_reset
+
+config_subdirs demo
diff --git a/window/cairo/xcb/demo/Makefile b/window/cairo/xcb/demo/Makefile
new file mode 100644
index 0000000..30365c8
--- /dev/null
+++ b/window/cairo/xcb/demo/Makefile
@@ -0,0 +1,99 @@
+## kc3
+## Copyright 2022-2024 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.
+
+CLEANFILES = *.a ${PROG} ${PROG_ASAN} ${PROG_COV} ${PROG_DEBUG} *.css \
+ *.gcno *.html *.o .libs *.lo
+
+CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
+CLEANFILES += ${CLEANFILES_COV}
+
+DISTCLEANFILES = ${CLEANFILES} config.mk
+
+build:
+ ${MAKE} ${PROG}
+
+all:
+ ${MAKE} build
+ if ${HAVE_GCOV}; then ${MAKE} cov; fi
+ ${MAKE} debug
+ if ${HAVE_ASAN}; then ${MAKE} asan; fi
+
+asan:
+ ${MAKE} ${PROG_ASAN}
+
+clean:
+ rm -rf ${CLEANFILES}
+
+clean_cov:
+ rm -rf ${CLEANFILES_COV}
+
+cov:
+ ${MAKE} ${PROG_COV}
+
+debug:
+ ${MAKE} ${PROG_DEBUG}
+
+demo:
+ ${MAKE} ${PROG}
+ time ./${PROG}
+
+demo_asan:
+ ${MAKE} ${PROG_ASAN}
+ time ./${PROG_ASAN}
+
+demo_cov:
+ ${MAKE} ${PROG_COV}
+ time ./${PROG_COV}
+
+demo_debug:
+ ${MAKE} ${PROG_DEBUG}
+ time ./${PROG_DEBUG}
+
+distclean:
+ rm -rf ${DISTCLEANFILES}
+
+gcovr:
+ gcovr --gcov-executable ${GCOV} --html-details ${PROG}.html
+
+gdb_demo: debug
+ if [ -f ${PROG_DEBUG}.core ]; then gdb .libs/${PROG_DEBUG} ${PROG_DEBUG}.core; else gdb .libs/${PROG_DEBUG}; fi
+
+install:
+ install -m 755 -d ${prefix}/bin
+ install -m 755 ${PROG} ${prefix}/bin/${PROG}
+
+lldb_demo: debug
+ if [ -f ${PROG_DEBUG}.core ]; then lldb .libs/${PROG_DEBUG} ${PROG_DEBUG}.core; else lldb .libs/${PROG_DEBUG}; fi
+
+update_sources:
+ ./update_sources
+
+.PHONY: \
+ all \
+ asan \
+ build \
+ clean \
+ clean_cov \
+ cov \
+ debug \
+ demo \
+ demo_asan \
+ demo_cov \
+ demo_debug \
+ distclean \
+ gdb_demo \
+ install \
+ lldb_demo \
+ update_sources \
+
+include config.mk
+include sources.mk
diff --git a/window/cairo/xcb/demo/configure b/window/cairo/xcb/demo/configure
new file mode 100755
index 0000000..9e16ca9
--- /dev/null
+++ b/window/cairo/xcb/demo/configure
@@ -0,0 +1,132 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+set -e
+
+echo "$PWD/configure"
+
+export SRC_TOP="$(dirname "$PWD")"
+
+. ../../../../config.subr
+
+PROG=kc3_window_cairo_xcb_demo
+PROG_ASAN=kc3_window_cairo_xcb_demo_asan
+PROG_COV=kc3_window_cairo_xcb_demo_cov
+PROG_DEBUG=kc3_window_cairo_xcb_demo_debug
+
+echo "PROG = $PROG" >> ${CONFIG_MK}
+echo "PROG_ASAN = $PROG_ASAN" >> ${CONFIG_MK}
+echo "PROG_COV = $PROG_COV" >> ${CONFIG_MK}
+echo "PROG_DEBUG = $PROG_DEBUG" >> ${CONFIG_MK}
+
+. ./sources.sh
+
+OBJECTS="$(c2ext .main.lo "$SOURCES")"
+echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
+
+OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
+echo "OBJECTS_ASAN = $OBJECTS_ASAN" >> ${CONFIG_MK}
+
+if $HAVE_GCOV; then
+ OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
+ echo "OBJECTS_COV = $OBJECTS_COV" >> ${CONFIG_MK}
+fi
+
+OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
+echo "OBJECTS_DEBUG = $OBJECTS_DEBUG" >> ${CONFIG_MK}
+
+# Common config for all targets
+CFLAGS="$CFLAGS -W -Wall -Werror -std=c11 -pedantic"
+CPPFLAGS="$CPPFLAGS -I../../../.."
+config_asan
+config_gnu
+config_i386
+pkg_config libbsd-overlay
+pkg_config libffi
+pkg_config libmd
+pkg_config xcb
+pkg_config cairo
+LIBS="$LIBS"
+
+# Asan config
+CPPFLAGS_ASAN="$CPPFLAGS"
+CFLAGS_ASAN="$CFLAGS -DDEBUG -O1 -g"
+CFLAGS_ASAN="$CFLAGS_ASAN -fsanitize=address -fno-omit-frame-pointer"
+LDFLAGS_ASAN="$LDFLAGS"
+LOCAL_LIBS_ASAN="../../../../libkc3/libkc3_asan.la"
+LOCAL_LIBS_ASAN="$LOCAL_LIBS_ASAN ../../../libkc3_window_asan.la"
+LOCAL_LIBS_ASAN="$LOCAL_LIBS_ASAN ../../libkc3_window_cairo_asan.la"
+LOCAL_LIBS_ASAN="$LOCAL_LIBS_ASAN ../../demo/libkc3_window_cairo_demo_asan.la"
+LOCAL_LIBS_ASAN="$LOCAL_LIBS_ASAN ../libkc3_window_cairo_xcb_asan.la"
+LIBS_ASAN="$LOCAL_LIBS_ASAN $LIBS"
+
+# Coverage config
+CPPFLAGS_COV="$CPPFLAGS"
+CFLAGS_COV="$CFLAGS -DDEBUG -fprofile-arcs -ftest-coverage"
+LDFLAGS_COV="$LDFLAGS --coverage"
+LOCAL_LIBS_COV="../../../../libkc3/libkc3_cov.la"
+LOCAL_LIBS_COV="$LOCAL_LIBS_COV ../../../libkc3_window_cov.la"
+LOCAL_LIBS_COV="$LOCAL_LIBS_COV ../../libkc3_window_cairo_cov.la"
+LOCAL_LIBS_COV="$LOCAL_LIBS_COV ../../demo/libkc3_window_cairo_demo_cov.la"
+LOCAL_LIBS_COV="$LOCAL_LIBS_COV ../libkc3_window_cairo_xcb_cov.la"
+LIBS_COV="$LOCAL_LIBS_COV $LIBS -lgcov"
+
+# Debug config
+CPPFLAGS_DEBUG="$CPPFLAGS"
+CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
+LDFLAGS_DEBUG="$LDFLAGS"
+LOCAL_LIBS_DEBUG="../../../../libkc3/libkc3_debug.la"
+LOCAL_LIBS_DEBUG="$LOCAL_LIBS_DEBUG ../../../libkc3_window_debug.la"
+LOCAL_LIBS_DEBUG="$LOCAL_LIBS_DEBUG ../../libkc3_window_cairo_debug.la"
+LOCAL_LIBS_DEBUG="$LOCAL_LIBS_DEBUG ../../demo/libkc3_window_cairo_demo_debug.la"
+LOCAL_LIBS_DEBUG="$LOCAL_LIBS_DEBUG ../libkc3_window_cairo_xcb_debug.la"
+LIBS_DEBUG="$LOCAL_LIBS_DEBUG $LIBS"
+
+# Main config
+DEFAULT_CFLAGS="-O2 -pipe -fPIC"
+if [ "x$ENV_CFLAGS" = "x" ]; then
+ CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
+fi
+CFLAGS="$CFLAGS -DNDEBUG"
+LOCAL_LIBS="../../../../libkc3/libkc3.la"
+LOCAL_LIBS="$LOCAL_LIBS ../../../libkc3_window.la"
+LOCAL_LIBS="$LOCAL_LIBS ../../libkc3_window_cairo.la"
+LOCAL_LIBS="$LOCAL_LIBS ../../demo/libkc3_window_cairo_demo.la"
+LOCAL_LIBS="$LOCAL_LIBS ../libkc3_window_cairo_xcb.la"
+LIBS="$LOCAL_LIBS $LIBS"
+
+echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
+echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
+echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
+echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
+echo "LIBS = $LIBS" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
+echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
+echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
+
+update_build
+update_build_prog
+
+build_lo
+build_prog
+
+update_config_mk
diff --git a/window/cairo/xcb/demo/sources.mk b/window/cairo/xcb/demo/sources.mk
new file mode 100644
index 0000000..e48fc91
--- /dev/null
+++ b/window/cairo/xcb/demo/sources.mk
@@ -0,0 +1,7 @@
+# sources.mk generated by update_sources
+HEADERS = \
+ "" \
+
+SOURCES = \
+ "window_cairo_xcb_demo.c" \
+
diff --git a/window/cairo/xcb/demo/sources.sh b/window/cairo/xcb/demo/sources.sh
new file mode 100644
index 0000000..4fbe5a1
--- /dev/null
+++ b/window/cairo/xcb/demo/sources.sh
@@ -0,0 +1,3 @@
+# sources.sh generated by update_sources
+HEADERS=' '
+SOURCES='window_cairo_xcb_demo.c '
diff --git a/window/cairo/xcb/demo/update_sources b/window/cairo/xcb/demo/update_sources
new file mode 100755
index 0000000..904d0bd
--- /dev/null
+++ b/window/cairo/xcb/demo/update_sources
@@ -0,0 +1,29 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+. ../../../../config.subr
+
+echo "$PWD/update_sources"
+
+echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
+echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
+
+HEADERS=
+#HEADERS="$(ls *.h | grep -v '^config.h$')"
+sources HEADERS "$HEADERS"
+
+SOURCES="$(ls *.c)"
+sources SOURCES "$SOURCES"
+
+update_sources_mk
+update_sources_sh
diff --git a/window/cairo/xcb/demo/window_cairo_xcb_demo.c b/window/cairo/xcb/demo/window_cairo_xcb_demo.c
new file mode 100644
index 0000000..bce4056
--- /dev/null
+++ b/window/cairo/xcb/demo/window_cairo_xcb_demo.c
@@ -0,0 +1,46 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <stdio.h>
+#include <stdlib.h>
+#include <libkc3/kc3.h>
+#include "../../window_cairo.h"
+#include "../../demo/window_cairo_demo.h"
+#include "../window_cairo_xcb.h"
+
+int main (int argc, char **argv)
+{
+ s_window_cairo window;
+ if (! kc3_init(NULL, &argc, &argv)) {
+ err_puts("kc3_init");
+ return 1;
+ }
+ kc3_window_cairo_init();
+ window_cairo_init(&window, 0, 0, 800, 600,
+ "KC3.Window.Cairo.XCB demo",
+ WINDOW_CAIRO_DEMO_SEQUENCE_COUNT);
+ window.button = window_cairo_demo_button;
+ window.key = window_cairo_demo_key;
+ window.load = window_cairo_demo_load;
+ window.render = window_cairo_demo_render;
+ window.resize = window_cairo_demo_resize;
+ window.unload = window_cairo_demo_unload;
+ if (! window_cairo_xcb_run(&window)) {
+ err_puts("window_cairo_xcb_run -> false");
+ window_cairo_clean(&window);
+ kc3_clean(NULL);
+ return g_kc3_exit_code;
+ }
+ window_cairo_clean(&window);
+ kc3_clean(NULL);
+ return 0;
+}
diff --git a/window/cairo/xcb/sources.mk b/window/cairo/xcb/sources.mk
new file mode 100644
index 0000000..aa817cf
--- /dev/null
+++ b/window/cairo/xcb/sources.mk
@@ -0,0 +1,7 @@
+# sources.mk generated by update_sources
+HEADERS = \
+ "window_cairo_xcb.h" \
+
+SOURCES = \
+ "window_cairo_xcb.c" \
+
diff --git a/window/cairo/xcb/sources.sh b/window/cairo/xcb/sources.sh
new file mode 100644
index 0000000..7890149
--- /dev/null
+++ b/window/cairo/xcb/sources.sh
@@ -0,0 +1,3 @@
+# sources.sh generated by update_sources
+HEADERS='window_cairo_xcb.h '
+SOURCES='window_cairo_xcb.c '
diff --git a/window/cairo/xcb/update_sources b/window/cairo/xcb/update_sources
new file mode 100755
index 0000000..abe35fb
--- /dev/null
+++ b/window/cairo/xcb/update_sources
@@ -0,0 +1,30 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+. ../../../config.subr
+
+echo "$PWD/update_sources"
+
+echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
+echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
+
+HEADERS="$(ls *.h | grep -v '^config.h$')"
+sources HEADERS "$HEADERS"
+
+SOURCES="$(ls *.c)"
+sources SOURCES "$SOURCES"
+
+update_sources_mk
+update_sources_sh
+
+( cd demo && ./update_sources; )
diff --git a/window/cairo/xcb/window_cairo_xcb.c b/window/cairo/xcb/window_cairo_xcb.c
new file mode 100644
index 0000000..4b41263
--- /dev/null
+++ b/window/cairo/xcb/window_cairo_xcb.c
@@ -0,0 +1,215 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <stdio.h>
+#include <stdlib.h>
+#include <cairo/cairo-xcb.h>
+#include <libkc3/kc3.h>
+#include <xcb/xcb.h>
+#include <xkbcommon/xkbcommon.h>
+#include <xkbcommon/xkbcommon-x11.h>
+#include "window_cairo_xcb.h"
+
+bool window_cairo_run (s_window_cairo *window)
+{
+ return window_cairo_xcb_run(window);
+}
+
+bool window_cairo_xcb_event (s_window_cairo *window,
+ xcb_connection_t *conn,
+ xcb_screen_t *screen,
+ xcb_visualtype_t *visual,
+ xcb_pixmap_t *pixmap,
+ cairo_surface_t **surface,
+ xcb_window_t xcb_window,
+ xcb_generic_event_t *event,
+ struct xkb_state *xkb_state)
+{
+ xcb_button_press_event_t *event_button;
+ xcb_configure_notify_event_t *event_config;
+ xcb_key_press_event_t *event_key;
+ xcb_motion_notify_event_t *event_motion;
+ switch (event->response_type & ~0x80) {
+ case XCB_BUTTON_PRESS:
+ event_button = (xcb_button_press_event_t *) event;
+ if (! window->button(window, event_button->detail,
+ event_button->event_x,
+ event_button->event_y))
+ goto ko;
+ break;
+ case XCB_EXPOSE:
+ if (! window->render(window))
+ goto ko;
+ xcb_gcontext_t gc = xcb_generate_id(conn);
+ u32 gc_mask = XCB_GC_GRAPHICS_EXPOSURES;
+ u32 gc_values[1] = {0};
+ xcb_create_gc(conn, gc, xcb_window, gc_mask, gc_values);
+ xcb_copy_area(conn, *pixmap, xcb_window, gc,
+ 0, 0, 0, 0, window->w, window->h);
+ xcb_flush(conn);
+ break;
+ case XCB_CONFIGURE_NOTIFY:
+ event_config = (xcb_configure_notify_event_t *) event;
+ if (! window->resize(window, event_config->width,
+ event_config->height))
+ goto ko;
+ window->w = event_config->width;
+ window->h = event_config->height;
+ cairo_destroy(window->cr);
+ cairo_surface_destroy(*surface);
+ xcb_free_pixmap(conn, *pixmap);
+ *pixmap = xcb_generate_id(conn);
+ xcb_create_pixmap(conn, screen->root_depth, *pixmap, xcb_window,
+ window->w, window->h);
+ *surface = cairo_xcb_surface_create(conn, *pixmap, visual, window->w,
+ window->h);
+ window->cr = cairo_create(*surface);
+ break;
+ case XCB_KEY_PRESS:
+ event_key = (xcb_key_press_event_t *) event;
+ xkb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state, event_key->detail);
+ if (! window->key(window, sym))
+ goto ko;
+ break;
+ case XCB_MOTION_NOTIFY:
+ event_motion = (xcb_motion_notify_event_t *) event;
+ if (! window->motion(window, event_motion->event_x,
+ event_motion->event_y))
+ goto ko;
+ break;
+ default:
+ printf("event type %d\n", event->response_type & ~0x80);
+ }
+ free(event);
+ return true;
+ ko:
+ free(event);
+ return false;
+}
+
+bool window_cairo_xcb_run (s_window_cairo *window)
+{
+ xcb_connection_t *conn;
+ xcb_generic_event_t *event;
+ xcb_pixmap_t pixmap;
+ bool r;
+ xcb_screen_t *screen;
+ xcb_visualtype_t *screen_visual;
+ s_timespec sleep;
+ cairo_surface_t *surface;
+ u32 value_mask;
+ u32 *value_list;
+ xcb_window_t xcb_window;
+ struct xkb_context *xkb_ctx;
+ int32_t xkb_device_id;
+ struct xkb_keymap *xkb_keymap;
+ struct xkb_state *xkb_state;
+ conn = xcb_connect(NULL, NULL);
+ if (xcb_connection_has_error(conn)) {
+ fprintf(stderr, "Error opening display.\n");
+ return false;
+ }
+ xkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+ if (!xkb_ctx) {
+ fprintf(stderr, "Failed to create XKB context\n");
+ return false;
+ }
+ xkb_x11_setup_xkb_extension(conn, 1, 0, 0, NULL, NULL, NULL, NULL);
+ xkb_device_id = xkb_x11_get_core_keyboard_device_id(conn);
+ if (xkb_device_id == -1) {
+ fprintf(stderr, "Failed to get XKB device ID\n");
+ return false;
+ }
+ xkb_keymap =
+ xkb_x11_keymap_new_from_device(xkb_ctx, conn, xkb_device_id,
+ XKB_KEYMAP_COMPILE_NO_FLAGS);
+ xkb_state = xkb_x11_state_new_from_device(xkb_keymap, conn,
+ xkb_device_id);
+ screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
+ screen_visual = xcb_screen_visual_type(screen);
+ xcb_window = xcb_generate_id(conn);
+ value_mask = XCB_CW_EVENT_MASK;
+ value_list = (u32[]) {XCB_EVENT_MASK_BUTTON_PRESS |
+ XCB_EVENT_MASK_EXPOSURE |
+ XCB_EVENT_MASK_KEY_PRESS |
+ XCB_EVENT_MASK_POINTER_MOTION |
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY};
+ xcb_create_window(conn, XCB_COPY_FROM_PARENT, xcb_window,
+ screen->root, window->x, window->y,
+ window->w, window->h, 0,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ screen->root_visual,
+ value_mask, value_list);
+ xcb_change_property(conn, XCB_PROP_MODE_REPLACE, xcb_window,
+ XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
+ strlen(window->title), window->title);
+ xcb_map_window(conn, xcb_window);
+ pixmap = xcb_generate_id(conn);
+ xcb_create_pixmap(conn, screen->root_depth, pixmap, xcb_window,
+ window->w, window->h);
+ surface = cairo_xcb_surface_create(conn, pixmap, screen_visual,
+ window->w, window->h);
+ window->cr = cairo_create(surface);
+ xcb_flush(conn);
+ if (! (r = window->load(window)))
+ goto clean;
+ while (1) {
+ if ((event = xcb_poll_for_event(conn))) {
+ if (! (r = window_cairo_xcb_event(window, conn, screen,
+ screen_visual, &pixmap,
+ &surface, xcb_window,
+ event, xkb_state)))
+ goto clean;
+ }
+ else {
+ sleep.tv_sec = 0;
+ sleep.tv_nsec = 1000000000 / 120;
+ nanosleep(&sleep, NULL);
+ xcb_expose_event_t event = {0};
+ event.response_type = XCB_EXPOSE;
+ event.window = xcb_window;
+ event.x = 0;
+ event.y = 0;
+ event.width = window->w;
+ event.height = window->h;
+ event.count = 0;
+ xcb_send_event(conn, false, xcb_window, XCB_EVENT_MASK_EXPOSURE, (const char *)&event);
+ xcb_flush(conn);
+ }
+ }
+ clean:
+ cairo_surface_destroy(surface);
+ cairo_destroy(window->cr);
+ xkb_state_unref(xkb_state);
+ xkb_keymap_unref(xkb_keymap);
+ xkb_context_unref(xkb_ctx);
+ xcb_disconnect(conn);
+ return r;
+}
+
+xcb_visualtype_t * xcb_screen_visual_type (xcb_screen_t *screen)
+{
+ xcb_depth_iterator_t depth_iter;
+ xcb_visualtype_iterator_t visual_iter;
+ depth_iter = xcb_screen_allowed_depths_iterator(screen);
+ while (depth_iter.rem) {
+ visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
+ while (visual_iter.rem) {
+ if (screen->root_visual == visual_iter.data->visual_id) {
+ return visual_iter.data;
+ }
+ xcb_visualtype_next(&visual_iter);
+ }
+ xcb_depth_next(&depth_iter);
+ }
+ return NULL;
+}
diff --git a/window/cairo/xcb/window_cairo_xcb.h b/window/cairo/xcb/window_cairo_xcb.h
new file mode 100644
index 0000000..6347bec
--- /dev/null
+++ b/window/cairo/xcb/window_cairo_xcb.h
@@ -0,0 +1,23 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_CAIRO_XCB_H
+#define LIBKC3_WINDOW_CAIRO_XCB_H
+
+#include <xcb/xcb.h>
+#include "../window_cairo.h"
+
+bool window_cairo_xcb_run (s_window_cairo *window);
+
+xcb_visualtype_t * xcb_screen_visual_type (xcb_screen_t *screen);
+
+#endif /* LIBKC3_WINDOW_CAIRO_XCB_H */
diff --git a/window/configure b/window/configure
new file mode 100755
index 0000000..52f09e4
--- /dev/null
+++ b/window/configure
@@ -0,0 +1,136 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+set -e
+
+echo "$PWD/configure"
+
+export SRC_TOP="$(dirname "$PWD")"
+
+CONFIG_H_PREFIX=LIBKC3_WINDOW_
+
+. ../config.subr
+
+LIB=libkc3_window.la
+LIB_ASAN=libkc3_window_asan.la
+LIB_COV=libkc3_window_cov.la
+LIB_DEBUG=libkc3_window_debug.la
+
+echo "LIB = $LIB" >> ${CONFIG_MK}
+echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
+echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
+echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
+
+. ./sources.sh
+
+OBJECTS="$(c2ext .main.lo "$SOURCES")"
+echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
+OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
+OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
+OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
+
+# Common config for all targets
+CPPFLAGS="-I.. $CPPFLAGS"
+CFLAGS="$CFLAGS -W -Wall -Werror -std=c11 -pedantic -pipe"
+LDFLAGS="--shared ${LDFLAGS} -rdynamic"
+config_asan
+config_gnu
+config_i386
+pkg_config libbsd-overlay
+pkg_config libffi
+pkg_config libmd
+config_define PREFIX "\"${PREFIX}\""
+LIBS="$LIBS -rpath ${PREFIX}/lib"
+
+# Address Sanitizer config
+CPPFLAGS_ASAN="$CPPFLAGS"
+CFLAGS_ASAN="$CFLAGS -DDEBUG -O1 -g"
+CFLAGS_ASAN="$CFLAGS_ASAN -fsanitize=address -fno-omit-frame-pointer"
+LDFLAGS_ASAN="$LDFLAGS"
+LIBS_LOCAL_ASAN="../libkc3/libkc3_asan.la"
+LIBS_ASAN="$LIBS_LOCAL_ASAN $LIBS"
+
+# Coverage config
+CPPFLAGS_COV="$CPPFLAGS"
+CFLAGS_COV="$CFLAGS --coverage"
+LDFLAGS_COV="$LDFLAGS"
+LIBS_LOCAL_COV="../libkc3/libkc3_cov.la"
+LIBS_COV="$LIBS_LOCAL_COV $LIBS"
+
+# Debug config
+CPPFLAGS_DEBUG="$CPPFLAGS"
+CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
+LDFLAGS_DEBUG="$LDFLAGS"
+LIBS_LOCAL_DEBUG="../libkc3/libkc3_debug.la"
+LIBS_DEBUG="$LIBS_LOCAL_DEBUG $LIBS"
+
+# Main config
+DEFAULT_CFLAGS="-O2 -pipe -fPIC"
+if [ "x$ENV_CFLAGS" = "x" ]; then
+ CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
+fi
+CFLAGS="$CFLAGS -DNDEBUG"
+LIBS_LOCAL="../libkc3/libkc3.la"
+LIBS="$LIBS_LOCAL $LIBS"
+
+echo "LIB = $LIB" >> ${CONFIG_MK}
+echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
+echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
+echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
+echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
+echo "LIBS = $LIBS" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
+echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
+echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
+echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
+echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
+echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
+
+update_build
+update_build_lib
+
+build_lo
+build_lib
+
+if pkg-config cairo; then
+ HAVE_CAIRO=true
+else
+ HAVE_CAIRO=false
+fi
+echo "HAVE_CAIRO = $HAVE_CAIRO" >> ${CONFIG_MK}
+
+if pkg-config sdl2; then
+ HAVE_SDL2=true
+else
+ HAVE_SDL2=false
+fi
+echo "HAVE_SDL2 = $HAVE_SDL2" >> ${CONFIG_MK}
+
+update_config_mk
+env_reset
+
+if ${HAVE_CAIRO}; then
+ config_subdirs cairo
+fi
+if ${HAVE_SDL2}; then
+ config_subdirs sdl2
+fi
diff --git a/window/sdl2/Makefile b/window/sdl2/Makefile
new file mode 100644
index 0000000..b9b5416
--- /dev/null
+++ b/window/sdl2/Makefile
@@ -0,0 +1,107 @@
+## kc3
+## Copyright 2022-2024 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.
+
+CLEANFILES = *.a *.gcno *.la .libs *.lo *.o
+
+CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
+
+CLEANFILES += ${CLEANFILES_COV}
+
+DISTCLEANFILES = ${CLEANFILES} config.h config.mk
+
+build:
+ ${MAKE} ${LIB}
+ ${MAKE} -C demo build
+
+all:
+ ${MAKE} build
+ ${MAKE} debug
+ if ${HAVE_ASAN}; then ${MAKE} asan; fi
+ if ${HAVE_GCOV}; then ${MAKE} cov; fi
+
+asan:
+ ${MAKE} ${LIB_ASAN}
+ ${MAKE} -C demo asan
+
+clean:
+ rm -rf ${CLEANFILES}
+ ${MAKE} -C demo clean
+
+clean_cov:
+ ${MAKE} -C demo clean_cov
+
+cov:
+ ${MAKE} ${LIB_COV}
+ ${MAKE} -C demo cov
+
+debug:
+ ${MAKE} ${LIB_DEBUG}
+ ${MAKE} -C demo debug
+
+demo: build
+ ${MAKE} -C demo demo
+
+demo_asan: asan
+ ${MAKE} -C demo demo_asan
+
+demo_cov: cov
+ ${MAKE} -C demo demo_cov
+
+demo_debug: debug
+ ${MAKE} -C demo demo_debug
+
+distclean:
+ rm -rf ${DISTCLEANFILES}
+ ${MAKE} -C demo distclean
+
+gcovr:
+ ${MAKE} -C demo gcovr
+
+gdb_demo: debug
+ ${MAKE} -C demo gdb_demo
+
+install:
+ ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0755 -d ${prefix}/include/libc3/window/sdl2
+ ${LIBTOOL} --tag=CC --mode=install ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0644 ${HEADERS} ${prefix}/include/libc3/window/sdl2
+ ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0755 -d ${prefix}/lib
+ ${LIBTOOL} --tag=CC --mode=install ${INSTALL} -o ${OWNER} -g ${GROUP} -m 0644 ${LIB} ${prefix}/lib
+ ${LIBTOOL} --finish ${prefix}/lib
+
+lldb_demo: debug
+ ${MAKE} -C demo lldb_demo
+
+test:
+ ${MAKE} -C demo test
+
+update_sources:
+ ./update_sources
+
+.PHONY: \
+ all \
+ asan \
+ build \
+ clean \
+ cov \
+ debug \
+ demo \
+ demo_asan \
+ demo_cov \
+ demo_debug \
+ distclean \
+ gdb_demo \
+ install \
+ lldb_demo \
+ test \
+ update_sources \
+
+include config.mk
+include sources.mk
diff --git a/window/sdl2/configure b/window/sdl2/configure
new file mode 100755
index 0000000..c2d1d93
--- /dev/null
+++ b/window/sdl2/configure
@@ -0,0 +1,123 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+set -e
+
+echo "$PWD/configure"
+
+export SRC_TOP="$(dirname "$PWD")"
+
+. ../../config.subr
+
+LIB=libkc3_window_sdl2.la
+LIB_ASAN=libkc3_window_sdl2_asan.la
+LIB_COV=libkc3_window_sdl2_cov.la
+LIB_DEBUG=libkc3_window_sdl2_debug.la
+
+echo "LIB = $LIB" >> ${CONFIG_MK}
+echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
+echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
+echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
+
+. ./sources.sh
+
+OBJECTS="$(c2ext .main.lo "$SOURCES")"
+echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
+OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
+OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
+OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
+
+# Common config for all targets
+CPPFLAGS="-I../.. $CPPFLAGS"
+CFLAGS="$CFLAGS -W -Wall -Werror -std=c11 -pedantic -pipe"
+LDFLAGS="--shared ${LDFLAGS}"
+config_asan
+config_gnu
+config_i386
+pkg_config libbsd-overlay
+pkg_config libmd
+pkg_config freetype2
+pkg_config gl
+pkg_config glew
+pkg_config glu
+pkg_config glut
+pkg_config libffi
+pkg_config libpng
+config_lib OPENGL -framework OpenGL
+pkg_config sdl2
+config_define PREFIX "\"${PREFIX}\""
+LIBS="$LIBS -rpath ${PREFIX}/lib"
+
+# Address Sanitizer config
+CPPFLAGS_ASAN="$CPPFLAGS"
+CFLAGS_ASAN="$CFLAGS -DDEBUG -O1 -g"
+CFLAGS_ASAN="$CFLAGS_ASAN -fsanitize=address -fno-omit-frame-pointer"
+LDFLAGS_ASAN="$LDFLAGS"
+LIBS_LOCAL_ASAN="../libkc3_window_asan.la"
+LIBS_ASAN="$LIBS_LOCAL_ASAN $LIBS"
+
+# Coverage config
+CPPFLAGS_COV="$CPPFLAGS"
+CFLAGS_COV="$CFLAGS -DDEBUG --coverage"
+LDFLAGS_COV="$LDFLAGS"
+LIBS_LOCAL_COV="../libkc3_window_cov.la"
+LIBS_COV="$LIBS_LOCAL_COV $LIBS"
+
+# Debug config
+CPPFLAGS_DEBUG="$CPPFLAGS"
+CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
+LDFLAGS_DEBUG="$LDFLAGS"
+LIBS_LOCAL_DEBUG="../libkc3_window_debug.la"
+LIBS_DEBUG="$LIBS_LOCAL_DEBUG $LIBS"
+
+# Main config
+DEFAULT_CFLAGS="-O2 -fPIC"
+if [ "x$ENV_CFLAGS" = "x" ]; then
+ CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
+fi
+CFLAGS="$CFLAGS -DNDEBUG"
+LIBS_LOCAL="../libkc3_window.la"
+LIBS="$LIBS_LOCAL $LIBS"
+
+echo "LIB = $LIB" >> ${CONFIG_MK}
+echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
+echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
+echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
+echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
+echo "LIBS = $LIBS" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_ASAN = $LIB_ASAN" >> ${CONFIG_MK}
+echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_COV = $LIB_COV" >> ${CONFIG_MK}
+echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
+echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
+echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "LIB_DEBUG = $LIB_DEBUG" >> ${CONFIG_MK}
+echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
+
+update_build
+update_build_lib
+
+build_lo
+build_lib
+
+update_config_mk
+env_reset
+
+config_subdirs demo
diff --git a/window/sdl2/demo/Makefile b/window/sdl2/demo/Makefile
new file mode 100644
index 0000000..c376721
--- /dev/null
+++ b/window/sdl2/demo/Makefile
@@ -0,0 +1,107 @@
+## kc3
+## Copyright 2022-2024 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.
+
+CLEANFILES = *.a ${PROG} ${PROG_ASAN} ${PROG_COV} ${PROG_DEBUG} *.css \
+ *.gcno *.html *.o .libs *.lo
+
+CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
+CLEANFILES += ${CLEANFILES_COV}
+
+DISTCLEANFILES = ${CLEANFILES} config.mk
+
+build:
+ ${MAKE} ${PROG}
+ if ${HAVE_DARWIN}; then ${MAKE} -C macos build; fi
+
+all:
+ ${MAKE} build
+ if ${HAVE_GCOV}; then ${MAKE} cov; fi
+ ${MAKE} debug
+ if ${HAVE_ASAN}; then ${MAKE} asan; fi
+
+asan:
+ ${MAKE} ${PROG_ASAN}
+ if ${HAVE_DARWIN}; then ${MAKE} -C macos asan; fi
+
+clean:
+ rm -rf ${CLEANFILES}
+ if ${HAVE_DARWIN}; then ${MAKE} -C macos clean; fi
+
+clean_cov:
+ rm -rf ${CLEANFILES_COV}
+ if ${HAVE_DARWIN}; then ${MAKE} -C macos clean_cov; fi
+
+cov:
+ ${MAKE} ${PROG_COV}
+ if ${HAVE_DARWIN}; then ${MAKE} -C macos cov; fi
+
+debug:
+ ${MAKE} ${PROG_DEBUG}
+ if ${HAVE_DARWIN}; then ${MAKE} -C macos debug; fi
+
+demo:
+ ${MAKE} ${PROG}
+ if ${HAVE_DARWIN}; then ${MAKE} -C macos demo; else time ./${PROG}; fi
+
+demo_asan:
+ ${MAKE} asan
+ if ${HAVE_DARWIN}; then ${MAKE} -C macos demo_asan; else time ./${PROG_ASAN}; fi
+
+demo_cov:
+ ${MAKE} cov
+ if ${HAVE_DARWIN}; then ${MAKE} -C macos demo_cov; else time ./${PROG_COV}; fi
+
+demo_debug:
+ ${MAKE} debug
+ if ${HAVE_DARWIN}; then ${MAKE} -C macos demo_debug; else time ./${PROG_DEBUG}; fi
+
+distclean:
+ rm -rf ${DISTCLEANFILES}
+ if ${HAVE_DARWIN}; then ${MAKE} -C macos distclean; fi
+
+gcovr:
+ gcovr --gcov-executable ${GCOV} --html-details ${PROG}.html
+ if ${HAVE_DARWIN}; then ${MAKE} -C macos gcovr; fi
+
+gdb_demo: debug
+ if ${HAVE_DARWIN}; then ${MAKE} -C macos gdb_demo; else gdb .libs/${PROG_DEBUG}; fi
+
+install:
+ install -m 755 -d ${prefix}/bin
+ install -m 755 ${PROG} ${prefix}/bin/${PROG}
+
+lldb_demo: debug
+ if ${HAVE_DARWIN}; then ${MAKE} -C macos lldb_demo; else lldb .libs/${PROG_DEBUG}; fi
+
+update_sources:
+ ./update_sources
+
+.PHONY: \
+ all \
+ asan \
+ build \
+ clean \
+ clean_cov \
+ cov \
+ debug \
+ demo \
+ demo_asan \
+ demo_cov \
+ demo_debug \
+ distclean \
+ gdb_demo \
+ install \
+ lldb_demo \
+ update_sources \
+
+include config.mk
+include sources.mk
diff --git a/window/sdl2/demo/bg_rect.c b/window/sdl2/demo/bg_rect.c
new file mode 100644
index 0000000..89cd649
--- /dev/null
+++ b/window/sdl2/demo/bg_rect.c
@@ -0,0 +1,61 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "../types.h"
+#include "bg_rect.h"
+
+bool bg_rect_load (s_sequence *seq)
+{
+ (void) seq;
+ return true;
+}
+
+bool bg_rect_render (s_sequence *seq)
+{
+#define BG_RECT_COLOR_MAX 8
+ const s_rgb color[BG_RECT_COLOR_MAX] = {
+ {0, 0, 0},
+ {1, 0, 0},
+ {1, 1, 0},
+ {0, 1, 0},
+ {0, 1, 1},
+ {0, 0, 1},
+ {1, 0, 1},
+ {1, 1, 1}
+ };
+ u8 c1;
+ u8 c2;
+ double p;
+ double q;
+ s_rgb rgb;
+ c1 = (u8) trunc(seq->t) % BG_RECT_COLOR_MAX;
+ c2 = (u8) trunc(seq->t + 1.0) % BG_RECT_COLOR_MAX;
+ p = fmod(seq->t, 1.0);
+ q = 1.0 - p;
+ rgb.r = color[c1].r * q + color[c2].r * p;
+ rgb.g = color[c1].g * q + color[c2].g * p;
+ rgb.b = color[c1].b * q + color[c2].b * p;
+ assert(glGetError() == GL_NO_ERROR);
+ glClearColor(rgb.r, rgb.g, rgb.b, 1.0);
+ assert(glGetError() == GL_NO_ERROR);
+ glClear(GL_COLOR_BUFFER_BIT);
+ assert(glGetError() == GL_NO_ERROR);
+ return true;
+}
+
+bool bg_rect_unload (s_sequence *seq)
+{
+ (void) seq;
+ return true;
+}
diff --git a/window/sdl2/demo/bg_rect.h b/window/sdl2/demo/bg_rect.h
new file mode 100644
index 0000000..144f39d
--- /dev/null
+++ b/window/sdl2/demo/bg_rect.h
@@ -0,0 +1,22 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 BG_RECT_H
+#define BG_RECT_H
+
+#include "../types.h"
+
+bool bg_rect_load (s_sequence *seq);
+bool bg_rect_render (s_sequence *seq);
+bool bg_rect_unload (s_sequence *seq);
+
+#endif /* BG_RECT_H */
diff --git a/window/sdl2/demo/configure b/window/sdl2/demo/configure
new file mode 100755
index 0000000..490f1e9
--- /dev/null
+++ b/window/sdl2/demo/configure
@@ -0,0 +1,145 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+set -e
+
+echo "$PWD/configure"
+
+export SRC_TOP="$(dirname "$PWD")"
+
+. ../../../config.subr
+
+PROG=kc3_window_sdl2_demo
+PROG_ASAN=kc3_window_sdl2_demo_asan
+PROG_COV=kc3_window_sdl2_demo_cov
+PROG_DEBUG=kc3_window_sdl2_demo_debug
+
+echo "PROG = $PROG" >> ${CONFIG_MK}
+echo "PROG_ASAN = $PROG_ASAN" >> ${CONFIG_MK}
+echo "PROG_COV = $PROG_COV" >> ${CONFIG_MK}
+echo "PROG_DEBUG = $PROG_DEBUG" >> ${CONFIG_MK}
+
+. ./sources.sh
+
+OBJECTS="$(c2ext .main.lo "$SOURCES")"
+echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
+
+OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
+echo "OBJECTS_ASAN = $OBJECTS_ASAN" >> ${CONFIG_MK}
+
+if $HAVE_GCOV; then
+ OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
+ echo "OBJECTS_COV = $OBJECTS_COV" >> ${CONFIG_MK}
+fi
+
+OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
+echo "OBJECTS_DEBUG = $OBJECTS_DEBUG" >> ${CONFIG_MK}
+
+# Common config for all targets
+CPPFLAGS="-I../../.. $CPPFLAGS"
+CFLAGS="$CFLAGS -W -Wall -Werror -Wno-error=unknown-pragmas"
+CFLAGS="$CFLAGS -std=c11 -pedantic -pipe"
+LIBS="$LIBS -lm"
+config_asan
+config_gnu
+config_i386
+pkg_config libbsd-overlay
+pkg_config libmd
+pkg_config freetype2
+pkg_config gl
+pkg_config glew
+pkg_config glu
+pkg_config glut
+pkg_config libffi
+pkg_config libpng
+config_lib OPENGL -framework OpenGL
+config_lib OPENGL -lopengl32 -lglu32
+config_lib OPENMP -fopenmp
+config_define HAVE_OPENMP "${HAVE_OPENMP}"
+pkg_config sdl2
+
+# Asan config
+CPPFLAGS_ASAN="$CPPFLAGS"
+CFLAGS_ASAN="$CFLAGS -DDEBUG -O1 -g"
+CFLAGS_ASAN="$CFLAGS_ASAN -fsanitize=address -fno-omit-frame-pointer"
+LDFLAGS_ASAN="$LDFLAGS"
+LOCAL_LIBS_ASAN="../../../libkc3/libkc3_asan.la"
+LOCAL_LIBS_ASAN="$LOCAL_LIBS_ASAN ../../libkc3_window_asan.la"
+LOCAL_LIBS_ASAN="$LOCAL_LIBS_ASAN ../libkc3_window_sdl2_asan.la"
+LIBS_ASAN="$LOCAL_LIBS_ASAN $LIBS"
+
+# Coverage config
+CPPFLAGS_COV="$CPPFLAGS"
+CFLAGS_COV="$CFLAGS -DDEBUG -fprofile-arcs -ftest-coverage"
+LDFLAGS_COV="$LDFLAGS --coverage"
+LOCAL_LIBS_COV="../../../libkc3/libkc3_cov.la"
+LOCAL_LIBS_COV="$LOCAL_LIBS_COV ../../libkc3_window_cov.la"
+LOCAL_LIBS_COV="$LOCAL_LIBS_COV ../libkc3_window_sdl2_cov.la"
+LIBS_COV="$LOCAL_LIBS_COV $LIBS -lgcov"
+
+# Debug config
+CPPFLAGS_DEBUG="$CPPFLAGS"
+CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -g"
+LDFLAGS_DEBUG="$LDFLAGS"
+LOCAL_LIBS_DEBUG="../../../libkc3/libkc3_debug.la"
+LOCAL_LIBS_DEBUG="$LOCAL_LIBS_DEBUG ../../libkc3_window_debug.la"
+LOCAL_LIBS_DEBUG="$LOCAL_LIBS_DEBUG ../libkc3_window_sdl2_debug.la"
+LIBS_DEBUG="$LOCAL_LIBS_DEBUG $LIBS"
+
+# Main config
+DEFAULT_CFLAGS="-O2 -fPIC"
+if [ "x$ENV_CFLAGS" = "x" ]; then
+ CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
+fi
+CFLAGS="$CFLAGS -DNDEBUG"
+LOCAL_LIBS="../../../libkc3/libkc3.la"
+LOCAL_LIBS="$LOCAL_LIBS ../../libkc3_window.la"
+LOCAL_LIBS="$LOCAL_LIBS ../libkc3_window_sdl2.la"
+LIBS="$LOCAL_LIBS $LIBS"
+
+echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
+echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
+echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
+echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
+echo "LIBS = $LIBS" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
+echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
+echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
+
+update_build
+update_build_prog
+
+build_lo
+build_prog
+
+if [ "x$(uname)" = "xDarwin" ]; then
+ HAVE_DARWIN=true
+else
+ HAVE_DARWIN=false
+fi
+echo "HAVE_DARWIN = $HAVE_DARWIN" >> ${CONFIG_MK}
+
+update_config_mk
+
+if ${HAVE_DARWIN}; then
+ config_subdirs macos
+fi
diff --git a/window/sdl2/demo/earth.c b/window/sdl2/demo/earth.c
new file mode 100644
index 0000000..45952dc
--- /dev/null
+++ b/window/sdl2/demo/earth.c
@@ -0,0 +1,122 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "../window_sdl2.h"
+#include "../gl_camera.h"
+#include "../mat4.h"
+#include "../gl_object.h"
+#include "../gl_sphere.h"
+#include "../gl_sprite.h"
+#include "earth.h"
+
+#define EARTH_CAMERA_ROTATION_Z_SPEED 0.1
+#define EARTH_SEGMENTS_U 200
+#define EARTH_SEGMENTS_V 100
+
+s_gl_sprite g_sprite_earth = {0};
+
+bool earth_load (s_sequence *seq)
+{
+ s_map *map;
+ s_mat4 matrix;
+ s_gl_camera *camera;
+ s_gl_sphere *sphere;
+ const f32 sphere_radius = 5.0;
+ s_window_sdl2 *window;
+ assert(seq);
+ window = seq->window;
+ assert(window);
+ camera = gl_camera_new(window->w, window->h);
+ if (! camera)
+ return false;
+ sphere = gl_sphere_new(EARTH_SEGMENTS_U, EARTH_SEGMENTS_V);
+ if (! sphere)
+ return false;
+ mat4_init_scale(&matrix, sphere_radius, sphere_radius,
+ sphere_radius);
+ gl_object_transform(&sphere->object, &matrix);
+ gl_object_update(&sphere->object);
+ if (! tag_map(&seq->tag, 3))
+ return false;
+ map = &seq->tag.data.map;
+ tag_init_sym( map->key + 0, sym_1("camera"));
+ tag_init_ptr_free( map->value + 0, camera);
+ tag_init_sym( map->key + 1, sym_1("camera_rot_x_speed"));
+ tag_init_f64( map->value + 1, 0.01);
+ tag_init_sym( map->key + 2, sym_1("sphere"));
+ tag_init_struct_with_data(map->value + 2, sym_1("GL.Sphere"),
+ sphere, false);
+ return true;
+}
+
+bool earth_render (s_sequence *seq)
+{
+ s_gl_camera *camera;
+ f64 *camera_rot_x_speed;
+ s_map *map;
+ s_gl_sphere *sphere;
+ s_window_sdl2 *window;
+ assert(seq);
+ window = seq->window;
+ assert(window);
+ if (! seq || seq->tag.type != TAG_MAP ||
+ seq->tag.data.map.count != 3) {
+ err_puts("earth_render: invalid seq->tag");
+ return false;
+ }
+ map = &seq->tag.data.map;
+ if (map->value[0].type != TAG_PTR_FREE ||
+ map->value[1].type != TAG_F64 ||
+ map->value[2].type != TAG_STRUCT) {
+ err_puts("earth_render: invalid map");
+ return false;
+ }
+ camera = map->value[0].data.ptr_free.p;
+ camera_rot_x_speed = &map->value[1].data.f64;
+ sphere = map->value[2].data.struct_.data;
+ gl_camera_set_aspect_ratio(camera, window->w, window->h);
+ camera->rotation.x += seq->dt * (*camera_rot_x_speed) *
+ M_PI * 2.0f;
+ if (camera->rotation.x > M_PI || camera->rotation.x < 0)
+ *camera_rot_x_speed *= -1.0;
+ camera->rotation.z += seq->dt * EARTH_CAMERA_ROTATION_Z_SPEED *
+ M_PI * 2.0f;
+ assert(glGetError() == GL_NO_ERROR);
+ gl_camera_render(camera);
+ assert(glGetError() == GL_NO_ERROR);
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ assert(glGetError() == GL_NO_ERROR);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ assert(glGetError() == GL_NO_ERROR);
+ assert(glGetError() == GL_NO_ERROR);
+ assert(glGetError() == GL_NO_ERROR);
+ assert(glGetError() == GL_NO_ERROR);
+ glEnable(GL_DEPTH_TEST);
+ assert(glGetError() == GL_NO_ERROR);
+ gl_camera_bind_texture(camera,
+ gl_sprite_texture(&g_sprite_earth, 0));
+ assert(glGetError() == GL_NO_ERROR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR_MIPMAP_LINEAR);
+ assert(glGetError() == GL_NO_ERROR);
+ gl_sphere_render(sphere);
+ glDisable(GL_DEPTH_TEST);
+ return true;
+}
+
+bool earth_unload (s_sequence *seq)
+{
+ (void) seq;
+ return true;
+}
diff --git a/window/sdl2/demo/earth.h b/window/sdl2/demo/earth.h
new file mode 100644
index 0000000..316618c
--- /dev/null
+++ b/window/sdl2/demo/earth.h
@@ -0,0 +1,26 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 EARTH_H
+#define EARTH_H
+
+#include "../types.h"
+#include "window_sdl2_demo.h"
+
+extern s_gl_sprite g_sprite_earth;
+extern s_gl_sprite g_sprite_earth_night;
+
+bool earth_load (s_sequence *seq);
+bool earth_render (s_sequence *seq);
+bool earth_unload (s_sequence *seq);
+
+#endif /* EARTH_H */
diff --git a/window/sdl2/demo/flies.c b/window/sdl2/demo/flies.c
new file mode 100644
index 0000000..74249cc
--- /dev/null
+++ b/window/sdl2/demo/flies.c
@@ -0,0 +1,360 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "../gl_font.h"
+#include "../mat4.h"
+#include "../gl_ortho.h"
+#include "../gl_text.h"
+#include "../gl_sprite.h"
+#include "../window_sdl2.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_gl_font g_font_flies = {0};
+s_gl_sprite g_sprite_dead_fly = {0};
+s_gl_sprite g_sprite_fly = {0};
+s_gl_text g_text_flies_in = {0};
+s_gl_text g_text_flies_out = {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->value[0].data.array;
+ in = &map->value[1].data.uw;
+ t = &map->value[3].data.f64;
+ array_data_set(board, address, &g_board_item_fly);
+ *t = 0.0;
+ (*in)++;
+}
+
+bool flies_load (s_sequence *seq)
+{
+ uw address[2];
+ s_array *board;
+ uw i;
+ uw j;
+ s_map *map;
+ tag_map(&seq->tag, 4);
+ map = &seq->tag.data.map;
+ tag_init_sym( map->key + 0, sym_1("board"));
+ tag_init_array(map->value + 0, sym_1("U8[]"),
+ 2, (uw[]) {BOARD_SIZE, BOARD_SIZE});
+ tag_init_sym( map->key + 1, sym_1("in"));
+ tag_init_uw( map->value + 1, 0);
+ tag_init_sym( map->key + 2, sym_1("out"));
+ tag_init_uw( map->value + 2, 0);
+ tag_init_sym( map->key + 3, sym_1("t"));
+ tag_init_uw( map->value + 3, 0);
+ board = &map->value[0].data.array;
+ array_allocate(board);
+ 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);
+ if (! gl_text_init_1(&g_text_flies_in, &g_font_flies, "In 0"))
+ return false;
+ gl_text_update(&g_text_flies_in);
+ if (! gl_text_init_1(&g_text_flies_out, &g_font_flies, "Out 0"))
+ return false;
+ gl_text_update(&g_text_flies_out);
+ return true;
+}
+
+bool flies_render (s_sequence *seq)
+{
+ char 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;
+ s_mat4 matrix;
+ s_mat4 matrix_1;
+ s_mat4 matrix_2;
+ uw r;
+ uw random_bits = 0;
+ f64 x;
+ f64 y;
+ s_window_sdl2 *window;
+ assert(seq);
+ window = seq->window;
+ assert(window);
+ glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ /* io_inspect(&seq->tag); */
+ if (!seq || seq->tag.type != TAG_MAP)
+ return false;
+ map = &seq->tag.data.map;
+ if (map->count != 4 ||
+ map->value[0].type != TAG_ARRAY ||
+ map->value[1].type != TAG_UW ||
+ map->value[2].type != TAG_UW ||
+ map->value[3].type != TAG_UW)
+ return false;
+ board = &map->value[0].data.array;
+ fly_in = &map->value[1].data.uw;
+ fly_out = &map->value[2].data.uw;
+ fly_time = &map->value[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_sprite_fly.pt_w;
+ dead_fly_scale = 2.0 * board_item_w / g_sprite_dead_fly.pt_w;
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR_MIPMAP_LINEAR);
+ mat4_init_identity(&g_ortho.model_matrix);
+ mat4_translate(&g_ortho.model_matrix, board_x, 60.0, 0.0);
+ gl_ortho_update_model_matrix(&g_ortho);
+ gl_ortho_color(&g_ortho, 1.0f, 1.0f, 1.0f, 1.0f);
+ buf_init(&buf, false, sizeof(a), a);
+ buf_write_1(&buf, "In ");
+ buf_inspect_uw(&buf, fly_in);
+ buf_write_u8(&buf, 0);
+ gl_font_set_size(&g_font_flies, board_item_h);
+ gl_text_update_1(&g_text_flies_in, a);
+ gl_ortho_text_render(&g_ortho, &g_text_flies_in);
+ buf_init(&buf, false, sizeof(a), a);
+ buf_write_1(&buf, "Out ");
+ buf_inspect_uw(&buf, fly_out);
+ buf_write_u8(&buf, 0);
+ gl_text_update_1(&g_text_flies_out, a);
+ matrix = g_ortho.model_matrix; {
+ x = board_item_w * (BOARD_SIZE / 2 + 1);
+ mat4_translate(&g_ortho.model_matrix, x, 0.0, 0.0);
+ gl_ortho_update_model_matrix(&g_ortho);
+ gl_ortho_text_render(&g_ortho, &g_text_flies_out);
+ g_ortho.model_matrix = matrix;
+ mat4_translate(&g_ortho.model_matrix, 0.0, board_item_h, 0.0);
+ gl_ortho_color(&g_ortho, 0.6f, 0.7f, 0.9f, 1.0f);
+ gl_ortho_rect(&g_ortho, 0, 0, board_w, board_h);
+ gl_ortho_color(&g_ortho, 1.0f, 1.0f, 1.0f, 1.0f);
+ 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];
+ matrix_1 = g_ortho.model_matrix; {
+ mat4_translate(&g_ortho.model_matrix, 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:
+ gl_ortho_bind_texture(&g_ortho, 0);
+ gl_ortho_color(&g_ortho, 0.0f, 0.0f, 1.0f, 1.0f);
+ gl_ortho_rect(&g_ortho, 0, 0, board_item_w + 1.0, board_item_h + 1.0);
+ gl_ortho_color(&g_ortho, 1.0f, 1.0f, 1.0f, 1.0f);
+ break;
+ case BOARD_ITEM_FLY:
+ matrix_2 = g_ortho.model_matrix; {
+ mat4_translate(&g_ortho.model_matrix,
+ -board_item_w / 2.0,
+ -board_item_h / 2.0, 0.0);
+ mat4_scale(&g_ortho.model_matrix, fly_scale,
+ fly_scale, 1.0);
+ gl_ortho_update_model_matrix(&g_ortho);
+ gl_ortho_bind_texture(&g_ortho,
+ gl_sprite_texture(&g_sprite_fly, 0));
+ gl_ortho_color(&g_ortho, 1.0f, 1.0f, 1.0f, 1.0f);
+ gl_ortho_rect(&g_ortho, 0, 0, g_sprite_fly.pt_w,
+ g_sprite_fly.pt_h);
+ gl_ortho_bind_texture(&g_ortho, 0);
+ } g_ortho.model_matrix = matrix_2;
+ 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 = arc4random();
+ random_bits = 32;
+ }
+ 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:
+ matrix_2 = g_ortho.model_matrix; {
+ mat4_translate(&g_ortho.model_matrix,
+ -board_item_w / 2.0,
+ -board_item_h / 2.0, 0.0);
+ mat4_scale(&g_ortho.model_matrix, dead_fly_scale,
+ dead_fly_scale, 1.0);
+ gl_ortho_update_model_matrix(&g_ortho);
+ gl_ortho_bind_texture(&g_ortho,
+ gl_sprite_texture(&g_sprite_dead_fly, 0));
+ gl_ortho_color(&g_ortho, 1.0f, 1.0f, 1.0f, 1.0f);
+ gl_ortho_rect(&g_ortho, 0, 0, g_sprite_dead_fly.pt_w,
+ g_sprite_dead_fly.pt_h);
+ gl_ortho_bind_texture(&g_ortho, 0);
+ } g_ortho.model_matrix = matrix_2;
+ break;
+ }
+ } g_ortho.model_matrix = matrix_1;
+ address[0]++;
+ }
+ address[1]++;
+ }
+ } g_ortho.model_matrix = matrix;
+ return true;
+}
+
+bool flies_unload (s_sequence *seq)
+{
+ (void) seq;
+ gl_text_clean(&g_text_flies_in);
+ gl_text_clean(&g_text_flies_out);
+ return true;
+}
diff --git a/window/sdl2/demo/flies.h b/window/sdl2/demo/flies.h
new file mode 100644
index 0000000..b6ac102
--- /dev/null
+++ b/window/sdl2/demo/flies.h
@@ -0,0 +1,27 @@
+/* kc3
+ * Copyright 2022,2023,2024 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_gl_font g_font_flies;
+extern s_gl_sprite g_sprite_dead_fly;
+extern s_gl_sprite g_sprite_fly;
+
+bool flies_load (s_sequence *seq);
+bool flies_render (s_sequence *seq);
+bool flies_unload (s_sequence *seq);
+
+#endif /* FLIES_H */
diff --git a/window/sdl2/demo/lightspeed.c b/window/sdl2/demo/lightspeed.c
new file mode 100644
index 0000000..7a50ca0
--- /dev/null
+++ b/window/sdl2/demo/lightspeed.c
@@ -0,0 +1,139 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "../gl_lines.h"
+#include "../mat4.h"
+#include "../gl_ortho.h"
+#include "../vec3.h"
+#include "window_sdl2_demo.h"
+#include "lightspeed.h"
+
+s_gl_lines g_lines_stars = {0};
+s_gl_ortho g_ortho_lightspeed = {0};
+
+static void star_init (s_tag *star)
+{
+ f64 x;
+ f64 y;
+ f64_random(&x);
+ f64_random(&y);
+ if (star->type != TAG_MAP || star->data.map.count != 3) {
+ tag_map(star, 3);
+ tag_init_sym(star->data.map.key + 0, sym_1("speed"));
+ tag_init_sym(star->data.map.key + 1, sym_1("x"));
+ tag_init_sym(star->data.map.key + 2, sym_1("y"));
+ }
+ tag_init_f64(star->data.map.value + 0, 0.0);
+ tag_init_f64(star->data.map.value + 1, 2.0 * x - 1.0);
+ tag_init_f64(star->data.map.value + 2, 2.0 * y - 1.0);
+}
+
+static void star_render (s_tag *star, s_sequence *seq, s_gl_vertex *v)
+{
+ f64 q;
+ f64 *speed;
+ f64 *x;
+ f64 *y;
+ if (star->type != TAG_MAP || star->data.map.count < 3)
+ star_init(star);
+ speed = &star->data.map.value[0].data.f64;
+ x = &star->data.map.value[1].data.f64;
+ y = &star->data.map.value[2].data.f64;
+ v[0].pos_x = *x;
+ v[0].pos_y = *y;
+ v[0].pos_z = 0.0;
+ q = (1 + *speed / 20);
+ v[1].pos_x = *x * q;
+ v[1].pos_y = *y * q;
+ v[1].pos_z = 0.0;
+ q = (1 + *speed / 100);
+ *x = *x * q;
+ *y = *y * q;
+ *speed += seq->dt;
+ if ((*x == 0.0 && *y == 0.0) ||
+ *x < -1.0 || *x > 1.0 ||
+ *y < -1.0 || *y > 1.0)
+ star_init(star);
+}
+
+bool lightspeed_load (s_sequence *seq)
+{
+ uw i;
+ uw star_count;
+ s_window_sdl2 *window;
+ assert(seq);
+ window = seq->window;
+ assert(window);
+ tag_tuple(&seq->tag, LIGHTSPEED_STAR_MAX);
+ star_count = window->w * window->h * LIGHTSPEED_STAR_PROBABILITY;
+ if (star_count > LIGHTSPEED_STAR_MAX)
+ star_count = LIGHTSPEED_STAR_MAX;
+ i = 0;
+ while (i < star_count) {
+ star_init(seq->tag.data.tuple.tag + i);
+ i++;
+ }
+ return true;
+}
+
+bool lightspeed_render (s_sequence *seq)
+{
+ uw i;
+ uw star_count;
+ s_gl_vertex *v;
+ s_window_sdl2 *window;
+ assert(seq);
+ window = seq->window;
+ assert(window);
+ mat4_init_identity(&g_ortho.model_matrix);
+ mat4_scale(&g_ortho.model_matrix, (f32) window->w / 2.0f,
+ (f32) window->h / 2.0f, 1.0f);
+ mat4_translate(&g_ortho.model_matrix, 1, 1, 0);
+ gl_ortho_update_model_matrix(&g_ortho);
+ star_count = window->w * window->h * LIGHTSPEED_STAR_PROBABILITY;
+ if (star_count > LIGHTSPEED_STAR_MAX)
+ star_count = LIGHTSPEED_STAR_MAX;
+ v = g_lines_stars.vertex.data;
+ i = 0;
+ while (i < star_count) {
+ star_render(seq->tag.data.tuple.tag + i, seq, v);
+ v += 2;
+ i++;
+ }
+ assert(glGetError() == GL_NO_ERROR);
+ gl_lines_update(&g_lines_stars, star_count);
+ assert(glGetError() == GL_NO_ERROR);
+ glDisable(GL_DEPTH_TEST);
+ assert(glGetError() == GL_NO_ERROR);
+ glClearColor(0, 0, 0, 1);
+ assert(glGetError() == GL_NO_ERROR);
+ glClear(GL_COLOR_BUFFER_BIT);
+ assert(glGetError() == GL_NO_ERROR);
+ glBlendColor(1, 1, 1, 0.7f);
+ assert(glGetError() == GL_NO_ERROR);
+ glEnable(GL_BLEND);
+ assert(glGetError() == GL_NO_ERROR);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ assert(glGetError() == GL_NO_ERROR);
+ glEnable(GL_LINE_SMOOTH);
+ assert(glGetError() == GL_NO_ERROR);
+ gl_lines_render(&g_lines_stars, star_count);
+ assert(glGetError() == GL_NO_ERROR);
+ return true;
+}
+
+bool lightspeed_unload (s_sequence *seq)
+{
+ (void) seq;
+ return true;
+}
diff --git a/window/sdl2/demo/lightspeed.h b/window/sdl2/demo/lightspeed.h
new file mode 100644
index 0000000..4c3889f
--- /dev/null
+++ b/window/sdl2/demo/lightspeed.h
@@ -0,0 +1,27 @@
+/* kc3
+ * Copyright 2022,2023,2024 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_STAR_MAX (1024 * 1024)
+#define LIGHTSPEED_STAR_PROBABILITY 0.005
+
+extern s_gl_lines g_lines_stars;
+
+bool lightspeed_load (s_sequence *seq);
+bool lightspeed_render (s_sequence *seq);
+bool lightspeed_unload (s_sequence *seq);
+
+#endif /* LIGHTSPEED_H */
diff --git a/window/sdl2/demo/macos/Makefile b/window/sdl2/demo/macos/Makefile
new file mode 100644
index 0000000..e294dd5
--- /dev/null
+++ b/window/sdl2/demo/macos/Makefile
@@ -0,0 +1,109 @@
+## kc3
+## Copyright 2022-2024 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.
+
+CLEANFILES = *.a ${APP_PROG} ${APP_PROG_ASAN} ${APP_PROG_COV} \
+ ${APP_PROG_DEBUG} ${PROG} ${PROG_ASAN} ${PROG_COV} ${PROG_DEBUG} \
+ *.css *.gcno *.html *.o .libs *.lo
+
+CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
+CLEANFILES += ${CLEANFILES_COV}
+
+DISTCLEANFILES = ${CLEANFILES} config.mk
+
+IMG_SOURCES = \
+ ../../../../img/earth.png \
+ ../../../../img/flaps.256.png \
+ ../../../../img/flaps.png \
+ ../../../../img/fly-dead.png \
+ ../../../../img/fly-noto.png \
+ ../../../../img/matrix_shade.png \
+ ../../../../img/toast.128.png \
+ ../../../../img/toast.png \
+
+FONT_SOURCES = \
+ ../../../../fonts/Courier\ New \
+ ../../../../fonts/Noto\ Sans \
+
+build:
+ ${MAKE} ${APP_PROG}
+ ${MAKE} ${APP}/Contents/Frameworks
+ rsync -aP --delete ../../../../lib ${APP}/Contents/
+ rsync -aP ${IMG_SOURCES} ${APP}/Contents/img/
+ rsync -aP ${FONT_SOURCES} ${APP}/Contents/fonts/
+
+all:
+ ${MAKE} build
+ if ${HAVE_GCOV}; then ${MAKE} cov; fi
+ ${MAKE} debug
+ if ${HAVE_ASAN}; then ${MAKE} asan; fi
+
+asan:
+ ${MAKE} ${APP_PROG_ASAN}
+ ${MAKE} ${APP_ASAN}/Contents/Frameworks
+ rsync -aP --delete ../../../../lib ${APP_ASAN}/Contents/
+ rsync -aP ${IMG_SOURCES} ${APP_ASAN}/Contents/img/
+ rsync -aP ${FONT_SOURCES} ${APP_ASAN}/Contents/fonts/
+
+clean:
+ rm -rf ${CLEANFILES}
+
+clean_cov:
+ rm -rf ${CLEANFILES_COV}
+
+cov:
+ ${MAKE} ${APP_PROG_COV}
+ ${MAKE} ${APP_COV}/Contents/Frameworks
+ rsync -aP --delete ../../../../lib ${APP_COV}/Contents/
+ rsync -aP ${IMG_SOURCES} ${APP_COV}/Contents/img/
+ rsync -aP ${FONT_SOURCES} ${APP_COV}/Contents/fonts/
+
+debug:
+ ${MAKE} ${APP_PROG_DEBUG}
+ ${MAKE} ${APP_DEBUG}/Contents/Frameworks
+ rsync -aP --delete ../../../../lib ${APP_DEBUG}/Contents/
+ rsync -aP ${IMG_SOURCES} ${APP_DEBUG}/Contents/img/
+ rsync -aP ${FONT_SOURCES} ${APP_DEBUG}/Contents/fonts/
+
+demo: build
+ time ${APP_PROG}
+
+demo_debug: debug
+ time ${APP_PROG_DEBUG}
+
+distclean:
+ rm -rf ${DISTCLEANFILES}
+
+gcovr:
+ gcovr --gcov-executable ${GCOV} --html-details ${PROG}.html
+
+gdb_demo: debug
+ if [ -f ${PROG_DEBUG}.core ]; then gdb .libs/${PROG_DEBUG} ${PROG_DEBUG}.core; else gdb .libs/${PROG_DEBUG}; fi
+
+lldb_demo: debug
+ lldb ${APP_PROG_DEBUG}
+
+install:
+ install -m 755 -d ${prefix}/bin
+ install -m 755 ${PROG} ${prefix}/bin/${PROG}
+
+.PHONY: \
+ all \
+ asan \
+ clean \
+ clean_cov \
+ cov \
+ debug \
+ demo \
+ distclean \
+ gdb_demo
+
+include config.mk
diff --git a/window/sdl2/demo/macos/c3_window_sdl2_demo.app/Contents/Info.plist b/window/sdl2/demo/macos/c3_window_sdl2_demo.app/Contents/Info.plist
new file mode 100644
index 0000000..16d4085
--- /dev/null
+++ b/window/sdl2/demo/macos/c3_window_sdl2_demo.app/Contents/Info.plist
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleExecutable</key>
+ <string>c3_window_sdl2_demo</string>
+ <key>CFBundleIconFile</key>
+ <string>c3</string>
+ <key>CFBundleIdentifier</key>
+ <string>io.kmx.c3-window-sdl2-demo</string>
+ <key>NSHighResolutionCapable</key>
+ <true/>
+</dict>
+</plist>
diff --git a/window/sdl2/demo/macos/c3_window_sdl2_demo.app/Contents/Resources/c3.icns b/window/sdl2/demo/macos/c3_window_sdl2_demo.app/Contents/Resources/c3.icns
new file mode 100644
index 0000000..377277a
Binary files /dev/null and b/window/sdl2/demo/macos/c3_window_sdl2_demo.app/Contents/Resources/c3.icns differ
diff --git a/window/sdl2/demo/macos/c3_window_sdl2_demo_debug.app/Contents/Info.plist b/window/sdl2/demo/macos/c3_window_sdl2_demo_debug.app/Contents/Info.plist
new file mode 100644
index 0000000..3e35f4c
--- /dev/null
+++ b/window/sdl2/demo/macos/c3_window_sdl2_demo_debug.app/Contents/Info.plist
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleExecutable</key>
+ <string>c3_window_sdl2_demo_debug</string>
+ <key>CFBundleIconFile</key>
+ <string>c3</string>
+ <key>CFBundleIdentifier</key>
+ <string>io.kmx.c3-window-sdl2-demo</string>
+ <key>NSHighResolutionCapable</key>
+ <true/>
+</dict>
+</plist>
diff --git a/window/sdl2/demo/macos/c3_window_sdl2_demo_debug.app/Contents/Resources/c3.icns b/window/sdl2/demo/macos/c3_window_sdl2_demo_debug.app/Contents/Resources/c3.icns
new file mode 100644
index 0000000..377277a
Binary files /dev/null and b/window/sdl2/demo/macos/c3_window_sdl2_demo_debug.app/Contents/Resources/c3.icns differ
diff --git a/window/sdl2/demo/macos/configure b/window/sdl2/demo/macos/configure
new file mode 100755
index 0000000..d4c12e8
--- /dev/null
+++ b/window/sdl2/demo/macos/configure
@@ -0,0 +1,132 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+set -e
+
+export SRC_TOP="$(dirname "$PWD")"
+
+. ../../../../config.subr
+
+PROG=kc3_window_sdl2_demo
+PROG_ASAN=kc3_window_sdl2_demo_asan
+PROG_COV=kc3_window_sdl2_demo_cov
+PROG_DEBUG=kc3_window_sdl2_demo_debug
+
+echo "PROG = $PROG" >> ${CONFIG_MK}
+echo "PROG_ASAN = $PROG_ASAN" >> ${CONFIG_MK}
+echo "PROG_COV = $PROG_COV" >> ${CONFIG_MK}
+echo "PROG_DEBUG = $PROG_DEBUG" >> ${CONFIG_MK}
+
+APP=kc3_window_sdl2_demo.app
+APP_ASAN=kc3_window_sdl2_demo_asan.app
+APP_COV=kc3_window_sdl2_demo_cov.app
+APP_DEBUG=kc3_window_sdl2_demo_debug.app
+
+echo "APP = $APP" >> ${CONFIG_MK}
+echo "APP_ASAN = ${APP_ASAN}" >> ${CONFIG_MK}
+echo "APP_COV = ${APP_COV}" >> ${CONFIG_MK}
+echo "APP_DEBUG = ${APP_DEBUG}" >> ${CONFIG_MK}
+
+APP_PROG=${APP}/Contents/MacOS/${PROG}
+APP_PROG_ASAN=${APP_ASAN}/Contents/MacOS/${PROG_ASAN}
+APP_PROG_COV=${APP_COV}/Contents/MacOS/${PROG_COV}
+APP_PROG_DEBUG=${APP_DEBUG}/Contents/MacOS/${PROG_DEBUG}
+
+echo "APP_PROG = $APP_PROG" >> ${CONFIG_MK}
+echo "APP_PROG_ASAN = $APP_PROG_ASAN" >> ${CONFIG_MK}
+echo "APP_PROG_COV = $APP_PROG_COV" >> ${CONFIG_MK}
+echo "APP_PROG_DEBUG = $APP_PROG_DEBUG" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "${APP_PROG}: ../.libs/${PROG}" >> ${CONFIG_MK}
+echo " mkdir -p ${APP}/Contents/MacOS" >> ${CONFIG_MK}
+echo " cp ../.libs/${PROG} ${APP_PROG}" >> ${CONFIG_MK}
+
+BUNDLE_LIBS_COMMON="/opt/homebrew/lib/libSDL2.dylib"
+
+BUNDLE_LIBS="${BUNDLE_LIBS_COMMON} ../../../../libkc3/.libs/libkc3.0.dylib ../../../.libs/libkc3_window.0.dylib ../../.libs/libkc3_window_sdl2.0.dylib"
+echo >> ${CONFIG_MK}
+echo "${APP}/Contents/Frameworks: ${BUNDLE_LIBS}" >> ${CONFIG_MK}
+echo " mkdir -p ${APP}/Contents/Frameworks" >> ${CONFIG_MK}
+echo " cp ${BUNDLE_LIBS} ${APP}/Contents/Frameworks/" >> ${CONFIG_MK}
+for BUNDLE_LIB in ${BUNDLE_LIBS}; do
+ L=$(basename $BUNDLE_LIB)
+ echo " install_name_tool -id @executable_path/../Frameworks/ ${APP}/Contents/Frameworks/$L" >> ${CONFIG_MK}
+ echo " install_name_tool -change ${LIBDIR}/$L @executable_path/../Frameworks/$L ${APP}/Contents/MacOS/${PROG}" >> ${CONFIG_MK}
+ echo " DEPS=\$\$(otool -L '${BUNDLE_LIB}' | awk '/^\t.+(\/usr\/lib|\/System)/ { next } /^\t/ { print \$\$1 }'); for DEP in \$\${DEPS}; do D=\$\$(basename \"\$\${DEP}\"); if [ -f ${APP}/Contents/Frameworks/\$\$D ]; then install_name_tool -change \$\${DEP} @executable_path/../Frameworks/\$\$D ${APP}/Contents/Frameworks/$L; fi; done" >> ${CONFIG_MK}
+done
+echo >> ${CONFIG_MK}
+echo ".PHONY: \\" >> ${CONFIG_MK}
+echo " ${APP}/Contents/Frameworks" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "${APP_PROG_ASAN}: ../.libs/${PROG_ASAN}" >> ${CONFIG_MK}
+echo " mkdir -p ${APP_ASAN}/Contents/MacOS" >> ${CONFIG_MK}
+echo " cp ../.libs/${PROG_ASAN} ${APP_PROG_ASAN}" >> ${CONFIG_MK}
+
+BUNDLE_LIBS_ASAN="${BUNDLE_LIBS_COMMON} ../../../../libkc3/.libs/libkc3_asan.0.dylib ../../../.libs/libkc3_window_asan.0.dylib ../../.libs/libkc3_window_sdl2_asan.0.dylib"
+echo >> ${CONFIG_MK}
+echo "${APP_ASAN}/Contents/Frameworks: ${BUNDLE_LIBS_ASAN}" >> ${CONFIG_MK}
+echo " mkdir -p ${APP_ASAN}/Contents/Frameworks" >> ${CONFIG_MK}
+echo " cp ${BUNDLE_LIBS_ASAN} ${APP_ASAN}/Contents/Frameworks/" >> ${CONFIG_MK}
+for BUNDLE_LIB in ${BUNDLE_LIBS_ASAN}; do
+ L=$(basename $BUNDLE_LIB)
+ echo " install_name_tool -id @executable_path/../Frameworks/ ${APP_ASAN}/Contents/Frameworks/$L" >> ${CONFIG_MK}
+ echo " install_name_tool -change ${LIBDIR}/$L @executable_path/../Frameworks/$L ${APP_ASAN}/Contents/MacOS/${PROG_ASAN}" >> ${CONFIG_MK}
+ echo " DEPS=\$\$(otool -L '${BUNDLE_LIB}' | awk '/^\t.+(\/usr\/lib|\/System)/ { next } /^\t/ { print \$\$1 }'); for DEP in \$\${DEPS}; do D=\$\$(basename \"\$\${DEP}\"); if [ -f ${APP_ASAN}/Contents/Frameworks/\$\$D ]; then install_name_tool -change \$\${DEP} @executable_path/../Frameworks/\$\$D ${APP_ASAN}/Contents/Frameworks/$L; fi; done" >> ${CONFIG_MK}
+done
+echo >> ${CONFIG_MK}
+echo ".PHONY: \\" >> ${CONFIG_MK}
+echo " ${APP_ASAN}/Contents/Frameworks" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "${APP_PROG_COV}: ../.libs/${PROG_COV}" >> ${CONFIG_MK}
+echo " mkdir -p ${APP_COV}/Contents/MacOS" >> ${CONFIG_MK}
+echo " cp ../.libs/${PROG_COV} ${APP_PROG_COV}" >> ${CONFIG_MK}
+
+BUNDLE_LIBS_COV="${BUNDLE_LIBS_COMMON} ../../../../libkc3/.libs/libkc3_cov.0.dylib ../../../.libs/libkc3_window_cov.0.dylib ../../.libs/libkc3_window_sdl2_cov.0.dylib"
+echo >> ${CONFIG_MK}
+echo "${APP_COV}/Contents/Frameworks: ${BUNDLE_LIBS_COV}" >> ${CONFIG_MK}
+echo " mkdir -p ${APP_COV}/Contents/Frameworks" >> ${CONFIG_MK}
+echo " cp ${BUNDLE_LIBS_COV} ${APP_COV}/Contents/Frameworks/" >> ${CONFIG_MK}
+for BUNDLE_LIB in ${BUNDLE_LIBS_COV}; do
+ L=$(basename $BUNDLE_LIB)
+ echo " install_name_tool -id @executable_path/../Frameworks/ ${APP_COV}/Contents/Frameworks/$L" >> ${CONFIG_MK}
+ echo " install_name_tool -change ${LIBDIR}/$L @executable_path/../Frameworks/$L ${APP_COV}/Contents/MacOS/${PROG}" >> ${CONFIG_MK}
+ echo " DEPS=\$\$(otool -L '${BUNDLE_LIB}' | awk '/^\t.+(\/usr\/lib|\/System)/ { next } /^\t/ { print \$\$1 }'); for DEP in \$\${DEPS}; do D=\$\$(basename \"\$\${DEP}\"); if [ -f ${APP_COV}/Contents/Frameworks/\$\$D ]; then install_name_tool -change \$\${DEP} @executable_path/../Frameworks/\$\$D ${APP_COV}/Contents/Frameworks/$L; fi; done" >> ${CONFIG_MK}
+done
+echo >> ${CONFIG_MK}
+echo ".PHONY: \\" >> ${CONFIG_MK}
+echo " ${APP_COV}/Contents/Frameworks" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "${APP_PROG_DEBUG}: ../.libs/${PROG_DEBUG}" >> ${CONFIG_MK}
+echo " mkdir -p ${APP_DEBUG}/Contents/MacOS" >> ${CONFIG_MK}
+echo " cp ../.libs/${PROG_DEBUG} ${APP_PROG_DEBUG}" >> ${CONFIG_MK}
+
+BUNDLE_LIBS_DEBUG="${BUNDLE_LIBS_COMMON} ../../../../libkc3/.libs/libkc3_debug.0.dylib ../../../.libs/libkc3_window_debug.0.dylib ../../.libs/libkc3_window_sdl2_debug.0.dylib"
+echo >> ${CONFIG_MK}
+echo "${APP_DEBUG}/Contents/Frameworks: ${BUNDLE_LIBS_DEBUG}" >> ${CONFIG_MK}
+echo " mkdir -p ${APP_DEBUG}/Contents/Frameworks" >> ${CONFIG_MK}
+echo " cp ${BUNDLE_LIBS_DEBUG} ${APP_DEBUG}/Contents/Frameworks/" >> ${CONFIG_MK}
+for BUNDLE_LIB in ${BUNDLE_LIBS_DEBUG}; do
+ L=$(basename $BUNDLE_LIB)
+ echo " install_name_tool -id @executable_path/../Frameworks/ ${APP_DEBUG}/Contents/Frameworks/$L" >> ${CONFIG_MK}
+ echo " install_name_tool -change ${LIBDIR}/$L @executable_path/../Frameworks/$L ${APP_DEBUG}/Contents/MacOS/${PROG_DEBUG}" >> ${CONFIG_MK}
+ echo " DEPS=\$\$(otool -L '${BUNDLE_LIB}' | awk '/^\t.+(\/usr\/lib|\/System)/ { next } /^\t/ { print \$\$1 }'); for DEP in \$\${DEPS}; do D=\$\$(basename \"\$\${DEP}\"); if [ -f ${APP_DEBUG}/Contents/Frameworks/\$\$D ]; then install_name_tool -change \$\${DEP} @executable_path/../Frameworks/\$\$D ${APP_DEBUG}/Contents/Frameworks/$L; fi; done" >> ${CONFIG_MK}
+done
+echo >> ${CONFIG_MK}
+echo ".PHONY: \\" >> ${CONFIG_MK}
+echo " ${APP_DEBUG}/Contents/Frameworks" >> ${CONFIG_MK}
+
+update_config_mk
diff --git a/window/sdl2/demo/mandelbrot_f128.c b/window/sdl2/demo/mandelbrot_f128.c
new file mode 100644
index 0000000..76e5208
--- /dev/null
+++ b/window/sdl2/demo/mandelbrot_f128.c
@@ -0,0 +1,320 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "../gl_deprecated.h"
+#include "../gl_font.h"
+#include "../mat4.h"
+#include "../gl_ortho.h"
+#include "../gl_text.h"
+#include "mandelbrot_f128.h"
+#include "window_sdl2_demo.h"
+
+static s_gl_font g_mandelbrot_f128_font = {0};
+static s_gl_text g_mandelbrot_f128_text = {0};
+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_button (s_sequence *seq, u8 button, sw x, sw y)
+{
+ s_map *map;
+ f128 *next_x;
+ f128 *next_y;
+ f128 *next_z;
+ s_window_sdl2 *win;
+ assert(seq);
+ win = seq->window;
+ assert(win);
+ 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;
+ if (button == 1) {
+ *next_x = *next_x + *next_z * (x - (f128) win->w / 2);
+ *next_y = *next_y + *next_z * ((f128) win->h / 2 - y);
+ }
+ else if (button == 5) {
+ *next_z = *next_z * exp2l(0.5);
+ }
+ else if (button == 4) {
+ *next_z = *next_z * exp2l(-0.5);
+ }
+ return true;
+}
+
+bool mandelbrot_f128_load (s_sequence *seq)
+{
+ f32 point_per_pixel;
+ s_map *map;
+ s_window_sdl2 *window;
+ assert(seq);
+ window = seq->window;
+ assert(window);
+ point_per_pixel = (f32) window->w / window->gl_w;
+ 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("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.0);
+ if (! gl_font_init(&g_mandelbrot_f128_font,
+ "fonts/Courier New/Courier New.ttf",
+ point_per_pixel))
+ return false;
+ gl_font_set_size(&g_mandelbrot_f128_font, 20.0);
+ if (! gl_text_init_1(&g_mandelbrot_f128_text, &g_mandelbrot_f128_font,
+ "x: 0.0\n"
+ "y: 0.0\n"
+ "z: 0.01"))
+ return false;
+ gl_text_update(&g_mandelbrot_f128_text);
+ assert(glGetError() == GL_NO_ERROR);
+ glGenTextures(1, &g_mandelbrot_f128_texture);
+ assert(glGetError() == GL_NO_ERROR);
+ return true;
+}
+
+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("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[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)
+ 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;
+ }
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ mat4_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);
+ gl_ortho_text_render_outline(&g_ortho, &g_mandelbrot_f128_text,
+ 20.0, 66.0);
+ 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, sym_1("U8[]"), 3, dim))
+ return false;
+ if (! array_allocate(pixels))
+ return false;
+ printf("mandelbrot_f128_resize: %lux%lu\n", win->w, win->h);
+ return true;
+}
+
+bool mandelbrot_f128_unload (s_sequence *seq)
+{
+ (void) seq;
+ glDeleteTextures(1, &g_mandelbrot_f128_texture);
+ gl_text_clean(&g_mandelbrot_f128_text);
+ gl_font_clean(&g_mandelbrot_f128_font);
+ return true;
+}
+
+static bool mandelbrot_f128_update (s_sequence *seq)
+{
+ f128 _2z_xz_y;
+ char a[512];
+ s_buf buf;
+ 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;
+ s_array *pixels;
+ u8 *pix;
+ 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);
+#pragma omp parallel for private(c_x, c_y, j, k, z_x, z_y, z_x2, z_y2, _2z_xz_y, level)
+ for (i = 0; i < win->h; i++) {
+ c_y = next_y + next_z * ((f128) i - win->h / 2);
+ j = 0;
+ while (j < win->w) {
+ c_x = next_x + next_z * ((f128) 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 = 255 - k;
+ /*if (k)
+ printf("x %lu, y %lu, k %d, level %d", j, i, k, level);*/
+ pix[(i * win->w + j) * 4 + 0] = level;
+ pix[(i * win->w + j) * 4 + 1] = level;
+ pix[(i * win->w + j) * 4 + 2] = level;
+ pix[(i * win->w + j) * 4 + 3] = 255;
+ j++;
+ }
+ }
+ assert(glGetError() == GL_NO_ERROR);
+ glBindTexture(GL_TEXTURE_2D, g_mandelbrot_f128_texture);
+ assert(glGetError() == GL_NO_ERROR);
+ 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_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ assert(glGetError() == GL_NO_ERROR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, win->w, win->h, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, pixels->data);
+ assert(glGetError() == GL_NO_ERROR);
+ buf_init(&buf, false, sizeof(a), a);
+ buf_write_1(&buf, "x: ");
+ buf_inspect_f128(&buf, &next_x);
+ buf_write_1(&buf, "\ny: ");
+ buf_inspect_f128(&buf, &next_y);
+ buf_write_1(&buf, "\nz: ");
+ buf_inspect_f128(&buf, &next_z);
+ gl_text_update_buf(&g_mandelbrot_f128_text, &buf);
+ printf("mandelbrot_f128_update: %lux%lu\n", win->w, win->h);
+ return true;
+}
diff --git a/window/sdl2/demo/mandelbrot_f128.h b/window/sdl2/demo/mandelbrot_f128.h
new file mode 100644
index 0000000..3a95d69
--- /dev/null
+++ b/window/sdl2/demo/mandelbrot_f128.h
@@ -0,0 +1,23 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 MANDELBROT_F128_H
+#define MANDELBROT_F128_H
+
+#include "../types.h"
+
+bool mandelbrot_f128_button (s_sequence *seq, u8 button, sw x, sw y);
+bool mandelbrot_f128_load (s_sequence *seq);
+bool mandelbrot_f128_render (s_sequence *seq);
+bool mandelbrot_f128_unload (s_sequence *seq);
+
+#endif /* MANDELBROT_F128_H */
diff --git a/window/sdl2/demo/matrix.c b/window/sdl2/demo/matrix.c
new file mode 100644
index 0000000..496029a
--- /dev/null
+++ b/window/sdl2/demo/matrix.c
@@ -0,0 +1,330 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "../gl_font.h"
+#include "../gl_ortho.h"
+#include "../gl_sprite.h"
+#include "../gl_vtext.h"
+#include "../mat4.h"
+#include "window_sdl2_demo.h"
+#include "matrix.h"
+
+#define MATRIX_FONT_SIZE 20
+#define MATRIX_TIME 0.1
+
+static s_gl_font g_matrix_font = {0};
+static s_gl_sprite g_matrix_shade = {0};
+static f64 g_matrix_time;
+
+void matrix_column_clean (s_tag *tag);
+bool matrix_column_init (s_sequence *seq, s_tag *tag);
+bool matrix_column_render (s_sequence *seq, s_tag *tag);
+void matrix_screen_clean (s_tag *tag);
+bool matrix_screen_init (s_tag *tag);
+bool matrix_screen_render (s_sequence *seq, s_tag *tag);
+void matrix_text_clean (s_tag *tag);
+bool matrix_text_init (s_tag *tag, f32 y);
+bool matrix_text_render (s_sequence *seq, const s_tag *tag, f32 **py);
+bool matrix_update (s_sequence *seq);
+
+void matrix_column_clean (s_tag *tag)
+{
+ s_list *list;
+ if (tag->type != TAG_LIST) {
+ err_puts("matrix_column_clean: invalid tag");
+ assert(! "matrix_column_clean: invalid tag");
+ return;
+ }
+ list = tag->data.list;
+ while (list) {
+ matrix_text_clean(&list->tag);
+ list = list_next(list);
+ }
+}
+
+bool matrix_column_init (s_sequence *seq, s_tag *tag)
+{
+ s_list *list;
+ s_window_sdl2 *window;
+ assert(seq);
+ window = seq->window;
+ assert(window);
+ if (! (list = list_new(NULL)))
+ return false;
+ if (! matrix_text_init(&list->tag, window->h)) {
+ list_delete_all(list);
+ return false;
+ }
+ tag_init_list(tag, list);
+ return true;
+}
+
+bool matrix_column_render (s_sequence *seq, s_tag *tag)
+{
+ s_list **list;
+ f32 *py;
+ s_window_sdl2 *window;
+ f32 y;
+ assert(seq);
+ assert(glGetError() == GL_NO_ERROR);
+ window = seq->window;
+ assert(window);
+ if (!tag ||
+ tag->type != TAG_LIST) {
+ err_puts("matrix_column_render: invalid tag");
+ assert(! "matrix_column_render: invalid tag");
+ return false;
+ }
+ list = &tag->data.list;
+ y = (*list)->tag.data.map.value[2].data.f32;
+ if (y < window->h) {
+ *list = list_new(*list);
+ if (! matrix_text_init(&(*list)->tag, window->h))
+ return false;
+ }
+ while (*list) {
+ if (! matrix_text_render(seq, &(*list)->tag, &py))
+ return false;
+ if (*py < 0) {
+ matrix_text_clean(&(*list)->tag);
+ *list = list_delete(*list);
+ }
+ else
+ list = &(*list)->next.data.list;
+ }
+ return true;
+}
+
+bool matrix_load (s_sequence *seq)
+{
+ f32 point_per_pixel;
+ s_window_sdl2 *window;
+ assert(seq);
+ assert(glGetError() == GL_NO_ERROR);
+ window = seq->window;
+ assert(window);
+ point_per_pixel = (f32) window->w / window->gl_w;
+ if (! gl_font_init(&g_matrix_font,
+ "fonts/Noto Sans/NotoSans-Regular.ttf",
+ point_per_pixel))
+ return false;
+ gl_font_set_size(&g_matrix_font, MATRIX_FONT_SIZE);
+ if (! matrix_screen_init(&seq->tag))
+ return false;
+ if (! gl_sprite_init(&g_matrix_shade,
+ "img/matrix_shade.png",
+ 1, 1, 1, 1))
+ return false;
+ g_matrix_time = seq->t;
+ return true;
+}
+
+bool matrix_render (s_sequence *seq)
+{
+ assert(seq);
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ assert(glGetError() == GL_NO_ERROR);
+ matrix_screen_render(seq, &seq->tag);
+ assert(glGetError() == GL_NO_ERROR);
+ if (seq->t - g_matrix_time > MATRIX_TIME)
+ g_matrix_time = seq->t;
+ return true;
+}
+
+void matrix_screen_clean (s_tag *tag)
+{
+ s_list *list;
+ if (! tag ||
+ tag->type != TAG_LIST) {
+ err_puts("matrix_screen_clean: invalid tag");
+ assert(! "matrix_screen_clean: invalid tag");
+ return;
+ }
+ list = tag->data.list;
+ while (list) {
+ matrix_column_clean(&list->tag);
+ list = list_next(list);
+ }
+}
+
+bool matrix_screen_init (s_tag *tag)
+{
+ tag_init_list(tag, NULL);
+ return true;
+}
+
+bool matrix_screen_render (s_sequence *seq, s_tag *tag)
+{
+ s_list **l;
+ s_list *list;
+ s_mat4 matrix;
+ s_window_sdl2 *window;
+ f32 x;
+ assert(seq);
+ window = seq->window;
+ assert(window);
+ if (! tag ||
+ tag->type != TAG_LIST) {
+ err_puts("matrix_screen_render: invalid tag");
+ assert(! "matrix_screen_render: invalid tag");
+ return false;
+ }
+ x = 0;
+ l = &tag->data.list;
+ while (*l) {
+ if (x > window->w) {
+ matrix_column_clean(&(*l)->tag);
+ *l = list_delete(*l);
+ }
+ else {
+ x += MATRIX_FONT_SIZE;
+ l = &(*l)->next.data.list;
+ }
+ }
+ while (x < window->w) {
+ *l = list_new(NULL);
+ if (! matrix_column_init(seq, &(*l)->tag))
+ return false;
+ x += MATRIX_FONT_SIZE;
+ l = &(*l)->next.data.list;
+ }
+ matrix = g_ortho.model_matrix; {
+ list = tag->data.list;
+ while (list) {
+ if (! matrix_column_render(seq, &list->tag))
+ return false;
+ mat4_translate(&g_ortho.model_matrix, MATRIX_FONT_SIZE, 0, 0);
+ list = list_next(list);
+ }
+ } g_ortho.model_matrix = matrix;
+ return true;
+}
+
+bool matrix_text_init (s_tag *tag, f32 y)
+{
+ char a[1024];
+ s_buf buf;
+ u8 i;
+ u8 len;
+ s_map *map;
+ f32 spacing;
+ s_gl_text *text;
+ if (! tag_map(tag, 3))
+ return false;
+ buf_init(&buf, false, sizeof(a), a);
+ u8_random_uniform(&i, 10);
+ spacing = i * MATRIX_FONT_SIZE;
+ u8_random_uniform(&len, 40);
+ len += 10;
+ text = gl_vtext_new(&g_matrix_font);
+ if (! text)
+ return false;
+ if (! gl_vtext_render_to_texture_random(text, len)) {
+ gl_vtext_delete(text);
+ return false;
+ }
+ map = &tag->data.map;
+ tag_init_sym( map->key + 0, sym_1("spacing"));
+ tag_init_f32(map->value + 0, spacing);
+ tag_init_sym( map->key + 1, sym_1("text"));
+ tag_init_ptr(map->value + 1, text);
+ tag_init_sym( map->key + 2, sym_1("y"));
+ tag_init_f32(map->value + 2, y + text->pt_h + spacing);
+ return true;
+}
+
+bool matrix_text_render (s_sequence *seq, const s_tag *tag, f32 **py)
+{
+ const s_map *map;
+ s_mat4 matrix;
+ const s_gl_text *text;
+ f32 *y;
+ assert(seq);
+ assert(glGetError() == GL_NO_ERROR);
+ assert(tag);
+ assert(tag->type == TAG_MAP);
+ map = &tag->data.map;
+ assert(map->count == 3);
+ /*
+ assert( map->key[0].type == TAG_SYM);
+ assert( map->key[0].data.sym == sym_1("spacing"));
+ assert( map->value[0].type == TAG_F32);
+ spacing = &map->value[0].data.f32;
+ */
+ assert( map->key[1].type == TAG_SYM);
+ assert( map->key[1].data.sym == sym_1("text"));
+ assert(map->value[1].type == TAG_PTR);
+ text = map->value[1].data.ptr.p;
+ assert( map->key[2].type == TAG_SYM);
+ assert( map->key[2].data.sym == sym_1("y"));
+ assert(map->value[2].type == TAG_F32);
+ y = &map->value[2].data.f32;
+ if (seq->t - g_matrix_time > MATRIX_TIME)
+ *y -= MATRIX_FONT_SIZE;
+ matrix = g_ortho.model_matrix; {
+ //printf("y %f\n", *y);
+ mat4_translate(&g_ortho.model_matrix,
+ (MATRIX_FONT_SIZE - text->pt_w) / 2, *y, 0);
+ gl_ortho_update_model_matrix(&g_ortho);
+ assert(glGetError() == GL_NO_ERROR);
+ gl_ortho_color(&g_ortho, 0, 1, 0, 1);
+ assert(glGetError() == GL_NO_ERROR);
+ glEnable(GL_BLEND);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
+ GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ gl_ortho_vtext_render(&g_ortho, text);
+ assert(glGetError() == GL_NO_ERROR);
+ glDisable(GL_DEPTH_TEST);
+ gl_ortho_color(&g_ortho, 1, 1, 1, 1);
+ gl_ortho_bind_texture(&g_ortho,
+ gl_sprite_texture(&g_matrix_shade, 0));
+ assert(glGetError() == GL_NO_ERROR);
+ gl_ortho_rect(&g_ortho, 0, MATRIX_FONT_SIZE - text->pt_h,
+ text->pt_w, text->pt_h - MATRIX_FONT_SIZE);
+ } g_ortho.model_matrix = matrix;
+ assert(glGetError() == GL_NO_ERROR);
+ glDisable(GL_BLEND);
+ assert(glGetError() == GL_NO_ERROR);
+ *py = y;
+ return true;
+}
+
+void matrix_text_clean (s_tag *tag)
+{
+ s_map *map;
+ s_gl_text *text;
+ if (! (tag->type == TAG_MAP &&
+ (map = &tag->data.map) &&
+ map->count == 3 &&
+ map->key[1].type == TAG_SYM &&
+ map->key[1].data.sym == sym_1("text") &&
+ map->value[1].type == TAG_PTR &&
+ (text = map->value[1].data.ptr.p))) {
+ err_puts("matrix_text_clean: invalid tag");
+ assert(! "matrix_text_clean: invalid tag");
+ return;
+ }
+ gl_vtext_delete(text);
+}
+
+bool matrix_unload (s_sequence *seq)
+{
+ assert(seq);
+ matrix_screen_clean(&seq->tag);
+ tag_void(&seq->tag);
+ gl_font_clean(&g_matrix_font);
+ gl_sprite_clean(&g_matrix_shade);
+ return true;
+}
diff --git a/window/sdl2/demo/matrix.h b/window/sdl2/demo/matrix.h
new file mode 100644
index 0000000..f97bc13
--- /dev/null
+++ b/window/sdl2/demo/matrix.h
@@ -0,0 +1,22 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 MATRIX_H
+#define MATRIX_H
+
+#include "../types.h"
+
+bool matrix_load (s_sequence *seq);
+bool matrix_render (s_sequence *seq);
+bool matrix_unload (s_sequence *seq);
+
+#endif /* MATRIX_H */
diff --git a/window/sdl2/demo/sources.mk b/window/sdl2/demo/sources.mk
new file mode 100644
index 0000000..95ffd97
--- /dev/null
+++ b/window/sdl2/demo/sources.mk
@@ -0,0 +1,21 @@
+# sources.mk generated by update_sources
+HEADERS = \
+ "bg_rect.h" \
+ "earth.h" \
+ "flies.h" \
+ "lightspeed.h" \
+ "mandelbrot_f128.h" \
+ "matrix.h" \
+ "toasters.h" \
+ "window_sdl2_demo.h" \
+
+SOURCES = \
+ "bg_rect.c" \
+ "earth.c" \
+ "flies.c" \
+ "lightspeed.c" \
+ "mandelbrot_f128.c" \
+ "matrix.c" \
+ "toasters.c" \
+ "window_sdl2_demo.c" \
+
diff --git a/window/sdl2/demo/sources.sh b/window/sdl2/demo/sources.sh
new file mode 100644
index 0000000..f2e1eca
--- /dev/null
+++ b/window/sdl2/demo/sources.sh
@@ -0,0 +1,3 @@
+# sources.sh generated by update_sources
+HEADERS='bg_rect.h earth.h flies.h lightspeed.h mandelbrot_f128.h matrix.h toasters.h window_sdl2_demo.h '
+SOURCES='bg_rect.c earth.c flies.c lightspeed.c mandelbrot_f128.c matrix.c toasters.c window_sdl2_demo.c '
diff --git a/window/sdl2/demo/toasters.c b/window/sdl2/demo/toasters.c
new file mode 100644
index 0000000..775fb1b
--- /dev/null
+++ b/window/sdl2/demo/toasters.c
@@ -0,0 +1,271 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "../mat4.h"
+#include "../gl_ortho.h"
+#include "../gl_sprite.h"
+#include "toasters.h"
+#include "window_sdl2_demo.h"
+
+#define TOASTERS_SCALE_TOAST 0.52
+#define TOASTERS_SCALE_TOASTER 0.4
+#define TOASTERS_SPACING \
+ (g_sprite_toaster.pt_h * TOASTERS_SCALE_TOASTER * 2.0)
+
+static const f64 g_speed_x = 80.0;
+static const f64 g_speed_y = -40.0;
+s_gl_sprite g_sprite_toast = {0};
+s_gl_sprite g_sprite_toaster = {0};
+
+static bool toasters_render_toasters (s_list **toasters,
+ s_window_sdl2 *window,
+ s_sequence *seq);
+static bool toasters_render_toasts (s_list **toasts,
+ s_window_sdl2 *window,
+ s_sequence *seq);
+
+static s_tag * toast_init (s_tag *toast, f64 x, f64 y)
+{
+ tag_init_map(toast, 2);
+ tag_init_sym(toast->data.map.key + 0, sym_1("x"));
+ tag_init_f64(toast->data.map.value + 0, x);
+ tag_init_sym(toast->data.map.key + 1, sym_1("y"));
+ tag_init_f64(toast->data.map.value + 1, y);
+ return toast;
+}
+
+
+static void toast_render (s_tag *toast, s_window_sdl2 *window,
+ s_sequence *seq)
+{
+ s_mat4 matrix;
+ GLuint texture;
+ f64 *x;
+ f64 *y;
+ if (toast->type == TAG_MAP) {
+ x = &toast->data.map.value[0].data.f64;
+ y = &toast->data.map.value[1].data.f64;
+ *x -= seq->dt * g_speed_x;
+ *y -= seq->dt * g_speed_y;
+ if (*x < -100 || *y > window->h) {
+ tag_clean(toast);
+ toast->type = TAG_VOID;
+ return;
+ }
+ matrix = g_ortho.model_matrix; {
+ mat4_translate(&g_ortho.model_matrix, *x,
+ *y + g_sprite_toast.pt_h, 0.0);
+ mat4_scale(&g_ortho.model_matrix,
+ TOASTERS_SCALE_TOAST,
+ -TOASTERS_SCALE_TOAST, 1);
+ gl_ortho_update_model_matrix(&g_ortho);
+ texture = gl_sprite_texture(&g_sprite_toast, 0);
+ gl_ortho_bind_texture(&g_ortho, texture);
+ gl_ortho_rect(&g_ortho, 0, 0, g_sprite_toast.pt_w,
+ g_sprite_toast.pt_h);
+ } g_ortho.model_matrix = matrix;
+ }
+}
+
+static s_tag * toaster_init (s_tag *toaster, f64 y)
+{
+ tag_init_map(toaster, 2);
+ tag_init_sym(toaster->data.map.key + 0, sym_1("x"));
+ tag_init_f64(toaster->data.map.value + 0, -150);
+ tag_init_sym(toaster->data.map.key + 1, sym_1("y"));
+ tag_init_f64(toaster->data.map.value + 1, y);
+ return toaster;
+}
+
+static void toaster_render (s_tag *toaster, s_window_sdl2 *window,
+ s_sequence *seq)
+{
+ s_mat4 matrix;
+ GLuint texture;
+ f64 *x;
+ f64 *y;
+ if (toaster->type == TAG_MAP) {
+ x = &toaster->data.map.value[0].data.f64;
+ y = &toaster->data.map.value[1].data.f64;
+ *x += seq->dt * g_speed_x;
+ *y += seq->dt * g_speed_y;
+ if (*x > window->w || *y < -300) {
+ tag_clean(toaster);
+ toaster->type = TAG_VOID;
+ return;
+ }
+ matrix = g_ortho.model_matrix;
+ mat4_translate(&g_ortho.model_matrix, *x,
+ *y + g_sprite_toaster.pt_h, 0.0);
+ mat4_scale(&g_ortho.model_matrix,
+ TOASTERS_SCALE_TOASTER,
+ -TOASTERS_SCALE_TOASTER, 1);
+ gl_ortho_update_model_matrix(&g_ortho);
+ texture = gl_sprite_texture(&g_sprite_toaster,
+ fmod(seq->t *
+ g_sprite_toaster.frame_count,
+ g_sprite_toaster.frame_count));
+ gl_ortho_bind_texture(&g_ortho, texture);
+ gl_ortho_rect(&g_ortho, 0, 0, g_sprite_toaster.pt_w,
+ g_sprite_toaster.pt_h);
+ g_ortho.model_matrix = matrix;
+ }
+}
+
+bool toasters_load (s_sequence *seq)
+{
+ s_map *map;
+ tag_map(&seq->tag, 2);
+ map = &seq->tag.data.map;
+ tag_init_sym( map->key + 0, sym_1("toasters"));
+ tag_init_list(map->value + 0, NULL);
+ tag_init_sym( map->key + 1, sym_1("toasts"));
+ tag_init_list(map->value + 1, NULL);
+ return true;
+}
+
+bool toasters_render (s_sequence *seq)
+{
+ s_list **toasters;
+ s_list **toasts;
+ s_window_sdl2 *window;
+ assert(seq);
+ window = seq->window;
+ assert(window);
+ glClearColor(0.7f, 0.95f, 1.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ mat4_init_identity(&g_ortho.model_matrix);
+ mat4_translate(&g_ortho.model_matrix, 0, window->h, 0);
+ mat4_scale(&g_ortho.model_matrix, 1, -1, 1);
+ /* io_inspect(&seq->tag); */
+ if (seq->tag.type == TAG_MAP) {
+ toasters = &seq->tag.data.map.value[0].data.list;
+ toasts = &seq->tag.data.map.value[1].data.list;
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR_MIPMAP_LINEAR);
+ toasters_render_toasts(toasts, window, seq);
+ toasters_render_toasters(toasters, window, seq);
+ }
+ return true;
+}
+
+bool toasters_render_toasts (s_list **toasts, s_window_sdl2 *window,
+ s_sequence *seq)
+{
+ s_list *i;
+ s_list *j;
+ s_map *map;
+ s_list **t = NULL;
+ f64 x;
+ f64 y;
+ assert(toasts);
+ assert(window);
+ assert(seq);
+ y = window->w * g_speed_y / g_speed_x -
+ TOASTERS_SPACING * 3.0 / 2.0 +
+ 50;
+ if (*toasts && (*toasts)->tag.type == TAG_MAP) {
+ t = &(*toasts)->tag.data.map.value[0].data.list;
+ y = (*toasts)->tag.data.map.value[1].data.f64;
+ }
+ while (y < window->h - TOASTERS_SPACING / 2) {
+ y += TOASTERS_SPACING;
+ *toasts = list_new_map(2, *toasts);
+ map = &(*toasts)->tag.data.map;
+ tag_init_sym( map->key + 0, sym_1("toasts"));
+ tag_init_list(map->value + 0, NULL);
+ tag_init_sym( map->key + 1, sym_1("y"));
+ tag_init_f64(map->value + 1, y);
+ }
+ i = *toasts;
+ while (i) {
+ if (i->tag.type == TAG_MAP) {
+ t = &i->tag.data.map.value[0].data.list;
+ y = i->tag.data.map.value[1].data.f64;
+ x = 0.0;
+ if (*t && (*t)->tag.type == TAG_MAP)
+ x = (*t)->tag.data.map.value[0].data.f64;
+ if (x < window->w - 160.0) {
+ *t = list_new(*t);
+ toast_init(&(*t)->tag, window->w, y);
+ }
+ list_remove_void(t);
+ j = *t;
+ while (j) {
+ toast_render(&j->tag, window, seq);
+ j = list_next(j);
+ }
+ }
+ i = list_next(i);
+ }
+ return true;
+}
+
+bool toasters_render_toasters (s_list **toasters, s_window_sdl2 *window,
+ s_sequence *seq)
+{
+ s_list *i;
+ s_list *j;
+ s_map *map;
+ s_list **t = NULL;
+ f64 x;
+ f64 y;
+ assert(toasters);
+ assert(window);
+ assert(seq);
+ /* io_inspect_list((const s_list **) toasters); */
+ y = -TOASTERS_SPACING - 40;
+ if (*toasters && (*toasters)->tag.type == TAG_MAP) {
+ t = &(*toasters)->tag.data.map.value[0].data.list;
+ y = (*toasters)->tag.data.map.value[1].data.f64;
+ }
+ while (y < window->h - window->w * g_speed_y / g_speed_x +
+ TOASTERS_SPACING) {
+ y += TOASTERS_SPACING;
+ *toasters = list_new_map(2, *toasters);
+ map = &(*toasters)->tag.data.map;
+ tag_init_sym( map->key + 0, sym_1("toasters"));
+ tag_init_list(map->value + 0, NULL);
+ tag_init_sym( map->key + 1, sym_1("y"));
+ tag_init_f64(map->value + 1, y);
+ }
+ i = *toasters;
+ while (i) {
+ if (i->tag.type == TAG_MAP) {
+ t = &i->tag.data.map.value[0].data.list;
+ y = i->tag.data.map.value[1].data.f64;
+ x = 1000.0;
+ if (*t && (*t)->tag.type == TAG_MAP)
+ x = (*t)->tag.data.map.value[0].data.f64;
+ if (x > 60.0) {
+ *t = list_new(*t);
+ toaster_init(&(*t)->tag, y);
+ }
+ list_remove_void(t);
+ j = *t;
+ while (j) {
+ toaster_render(&j->tag, window, seq);
+ j = list_next(j);
+ }
+ }
+ i = list_next(i);
+ }
+ return true;
+}
+
+bool toasters_unload (s_sequence *seq)
+{
+ (void) seq;
+ return true;
+}
diff --git a/window/sdl2/demo/toasters.h b/window/sdl2/demo/toasters.h
new file mode 100644
index 0000000..ab0a583
--- /dev/null
+++ b/window/sdl2/demo/toasters.h
@@ -0,0 +1,25 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 TOASTERS_H
+#define TOASTERS_H
+
+#include "../types.h"
+
+extern s_gl_sprite g_sprite_toast;
+extern s_gl_sprite g_sprite_toaster;
+
+bool toasters_load (s_sequence *seq);
+bool toasters_render (s_sequence *seq);
+bool toasters_unload (s_sequence *seq);
+
+#endif /* TOASTERS_H */
diff --git a/window/sdl2/demo/update_sources b/window/sdl2/demo/update_sources
new file mode 100755
index 0000000..0c17b11
--- /dev/null
+++ b/window/sdl2/demo/update_sources
@@ -0,0 +1,28 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+. ../../../config.subr
+
+echo "$PWD/update_sources"
+
+echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
+echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
+
+HEADERS="$(ls *.h | grep -v '^config.h$')"
+sources HEADERS "$HEADERS"
+
+SOURCES="$(ls *.c)"
+sources SOURCES "$SOURCES"
+
+update_sources_mk
+update_sources_sh
diff --git a/window/sdl2/demo/window_sdl2_demo.c b/window/sdl2/demo/window_sdl2_demo.c
new file mode 100644
index 0000000..955f14a
--- /dev/null
+++ b/window/sdl2/demo/window_sdl2_demo.c
@@ -0,0 +1,303 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <stdio.h>
+#include <stdlib.h>
+#include <libkc3/kc3.h>
+#include "../../window.h"
+#include "../gl_font.h"
+#include "../gl_lines.h"
+#include "../mat4.h"
+#include "../gl_ortho.h"
+#include "../gl_square.h"
+#include "../gl_text.h"
+#include "../gl_sprite.h"
+#include "../window_sdl2.h"
+#include "bg_rect.h"
+#include "lightspeed.h"
+#include "toasters.h"
+#include "flies.h"
+#include "earth.h"
+#include "mandelbrot_f128.h"
+#include "matrix.h"
+
+#define WINDOW_SDL2_DEMO_SEQUENCE_COUNT 7
+
+//s_gl_font g_font_computer_modern = {0};
+s_gl_font g_font_courier_new = {0};
+s_gl_ortho g_ortho = {0};
+s_gl_square g_square = {0};
+s_gl_text g_text_fps = {0};
+s_gl_text g_text_seq_title = {0};
+
+static bool window_sdl2_demo_button (s_window_sdl2 *window, u8 button,
+ sw x, sw y);
+static bool window_sdl2_demo_key (s_window_sdl2 *window,
+ SDL_Keysym *keysym);
+static bool window_sdl2_demo_load (s_window_sdl2 *window);
+static bool window_sdl2_demo_render (s_window_sdl2 *window);
+static bool window_sdl2_demo_resize (s_window_sdl2 *window,
+ uw w, uw h);
+static void window_sdl2_demo_unload (s_window_sdl2 *window);
+
+int main (int argc, char **argv)
+{
+ s_window_sdl2 window;
+ if (FT_Init_FreeType(&g_ft)) {
+ err_puts("main: failed to initialize FreeType");
+ return 1;
+ }
+ if (! kc3_init(NULL, &argc, &argv)) {
+ err_puts("kc3_init");
+ return 1;
+ }
+ window_sdl2_init(&window, 50, 50, 800, 600,
+ "KC3.Window.SDL2 demo",
+ WINDOW_SDL2_DEMO_SEQUENCE_COUNT);
+ window.button = window_sdl2_demo_button;
+ window.key = window_sdl2_demo_key;
+ window.load = window_sdl2_demo_load;
+ window.render = window_sdl2_demo_render;
+ window.resize = window_sdl2_demo_resize;
+ window.unload = window_sdl2_demo_unload;
+ if (! window_sdl2_run(&window)) {
+ err_puts("window_sdl2_run -> false");
+ window_sdl2_clean(&window);
+ kc3_clean(NULL);
+ SDL_Quit();
+ return g_kc3_exit_code;
+ }
+ window_sdl2_clean(&window);
+ kc3_clean(NULL);
+ SDL_Quit();
+ FT_Done_FreeType(g_ft);
+ return 0;
+}
+
+bool window_sdl2_demo_button (s_window_sdl2 *window, u8 button,
+ sw x, sw y)
+{
+ assert(window);
+ (void) window;
+ printf("kc3_window_sdl2_demo_button: %lu (%ld, %ld)\n", (uw) button, x, y);
+ if (window->seq && window->seq->button &&
+ ! window->seq->button(window->seq, button, x, y))
+ return false;
+ return true;
+}
+
+bool window_sdl2_demo_key (s_window_sdl2 *window, SDL_Keysym *keysym)
+{
+ assert(window);
+ assert(keysym);
+ (void) window;
+ switch (keysym->sym) {
+ case SDLK_f:
+ if (! window->fullscreen) {
+ if (SDL_SetWindowFullscreen(window->sdl_window,
+ SDL_WINDOW_FULLSCREEN_DESKTOP)) {
+ err_write_1("window_sdl2_demo_key:"
+ " SDL_SetWindowFullscreen(:desktop): ");
+ err_puts(SDL_GetError());
+ SDL_MaximizeWindow(window->sdl_window);
+ }
+ }
+ else {
+ if (SDL_SetWindowFullscreen(window->sdl_window, 0)) {
+ err_write_1("window_sdl2_demo_key:"
+ " SDL_SetWindowFullscreen(0): ");
+ err_puts(SDL_GetError());
+ SDL_RestoreWindow(window->sdl_window);
+ }
+ }
+ window->fullscreen = ! window->fullscreen;
+ return true;
+ case SDLK_ESCAPE:
+ case SDLK_q:
+ g_kc3_exit_code = 0;
+ return false;
+ case SDLK_LEFT:
+ if (! window_set_sequence_pos((s_window *) window,
+ (window->sequence_pos +
+ window->sequence_count - 1) %
+ window->sequence_count))
+ return false;
+ break;
+ case SDLK_RIGHT:
+ if (! window_set_sequence_pos((s_window *) window,
+ (window->sequence_pos + 1) %
+ window->sequence_count))
+ return false;
+ break;
+ default:
+ printf("kc3_window_sdl2_demo_key: %d\n", keysym->sym);
+ }
+ return true;
+}
+
+bool window_sdl2_demo_load (s_window_sdl2 *window)
+{
+ f32 point_per_pixel;
+ assert(window);
+ assert(glGetError() == GL_NO_ERROR);
+ point_per_pixel = (f32) window->w / window->gl_w;
+ err_write_1("point_per_pixel: ");
+ err_inspect_f32(&point_per_pixel);
+ err_write_1("\n");
+ if (window->sequence_count != WINDOW_SDL2_DEMO_SEQUENCE_COUNT) {
+ fprintf(stderr, "window_sdl2_demo_load: "
+ "window->sequence_count = %lu\n", window->sequence_count);
+ assert(window->sequence_count == WINDOW_SDL2_DEMO_SEQUENCE_COUNT);
+ return false;
+ }
+ if (! gl_ortho_init(&g_ortho))
+ return false;
+ gl_ortho_resize(&g_ortho, 0, window->w, 0, window->h, 0, 1);
+ if (! gl_font_init(&g_font_courier_new,
+ "fonts/Courier New/Courier New.ttf",
+ point_per_pixel))
+ return false;
+ if (! gl_text_init_1(&g_text_seq_title, &g_font_courier_new, ""))
+ return false;
+ if (! gl_text_init_1(&g_text_fps, &g_font_courier_new, "0.00"))
+ return false;
+ sequence_init(window->sequence, 8.0, "01. Background rectangles",
+ bg_rect_load, bg_rect_render, bg_rect_unload, window);
+ if (! gl_lines_init(&g_lines_stars) ||
+ ! gl_lines_allocate(&g_lines_stars, LIGHTSPEED_STAR_MAX))
+ return false;
+ sequence_init(window->sequence + 1, 20.0, "02. Lightspeed",
+ lightspeed_load, lightspeed_render, lightspeed_unload,
+ window);
+ if (! gl_sprite_init(&g_sprite_toaster, "img/flaps.256.png",
+ 4, 1, 4, 1))
+ return false;
+ if (! gl_sprite_init(&g_sprite_toast, "img/toast.128.png",
+ 1, 1, 1, 1))
+ return false;
+ sequence_init(window->sequence + 2, 60.0, "03. Toasters",
+ toasters_load, toasters_render, toasters_unload,
+ window);
+ if (! gl_font_init(&g_font_flies,
+ "fonts/Courier New/Courier New.ttf",
+ point_per_pixel))
+ return false;
+ if (! gl_sprite_init(&g_sprite_fly, "img/fly-noto.png",
+ 1, 1, 1, point_per_pixel))
+ return false;
+ if (! gl_sprite_init(&g_sprite_dead_fly, "img/fly-dead.png",
+ 1, 1, 1, point_per_pixel))
+ return false;
+ sequence_init(window->sequence + 3, 60.0, "04. Flies",
+ flies_load, flies_render, flies_unload, window);
+ if (! gl_sprite_init(&g_sprite_earth, "img/earth.png",
+ 1, 1, 1, point_per_pixel))
+ return false;
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ assert(glGetError() == GL_NO_ERROR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ assert(glGetError() == GL_NO_ERROR);
+ sequence_init(window->sequence + 4, 120.0, "05. Earth",
+ earth_load, earth_render, earth_unload, window);
+ sequence_init(window->sequence + 5, 3600.0, "06. Mandelbrot (f128)",
+ mandelbrot_f128_load, mandelbrot_f128_render,
+ mandelbrot_f128_unload, window);
+ window->sequence[5].button = mandelbrot_f128_button;
+ sequence_init(window->sequence + 6, 3600.0, "07. Matrix",
+ matrix_load, matrix_render,
+ matrix_unload, window);
+ window_set_sequence_pos((s_window *) window, 0);
+ return true;
+}
+
+bool window_sdl2_demo_render (s_window_sdl2 *window)
+{
+ s_sequence *seq;
+ assert(window);
+ assert(glGetError() == GL_NO_ERROR);
+ if (! window_animate((s_window *) window))
+ return false;
+ seq = window->seq;
+ mat4_init_identity(&g_ortho.model_matrix);
+ gl_ortho_render(&g_ortho);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_BLEND);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
+ GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ assert(glGetError() == GL_NO_ERROR);
+ if (! seq->render(seq))
+ return false;
+ assert(glGetError() == GL_NO_ERROR);
+ /* 2D */
+ gl_ortho_render(&g_ortho);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_BLEND);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
+ GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ assert(glGetError() == GL_NO_ERROR);
+ gl_font_set_size(&g_font_courier_new, 20);
+ gl_text_update_1(&g_text_seq_title, seq->title);
+ mat4_init_identity(&g_ortho.model_matrix);
+ gl_ortho_text_render_outline(&g_ortho, &g_text_seq_title,
+ 20.0f, 30.0f);
+ /* progress bar */
+ mat4_init_identity(&g_ortho.model_matrix);
+ glDisable(GL_BLEND);
+ assert(glGetError() == GL_NO_ERROR);
+ gl_ortho_bind_texture(&g_ortho, 0);
+ assert(glGetError() == GL_NO_ERROR);
+ gl_ortho_color(&g_ortho, 1.0f, 1.0f, 1.0f, 1.0f);
+ gl_ortho_rect(&g_ortho, 19, 11,
+ (window->w - 40.0) * seq->t / seq->duration + 2,
+ 4);
+ gl_ortho_color(&g_ortho, 0.0f, 0.0f, 0.0f, 1.0f);
+ gl_ortho_rect(&g_ortho, 20, 12,
+ (window->w - 40.0) * seq->t / seq->duration,
+ 2);
+ /* fps */
+ char fps[32];
+ snprintf(fps, sizeof(fps), "%.1f", (f64) seq->frame / seq->t);
+ mat4_init_identity(&g_ortho.model_matrix);
+ gl_text_update_1(&g_text_fps, fps);
+ glEnable(GL_BLEND);
+ gl_ortho_text_render_outline(&g_ortho, &g_text_fps,
+ 20, window->h - 30);
+ gl_ortho_render_end(&g_ortho);
+ return true;
+}
+
+bool window_sdl2_demo_resize (s_window_sdl2 *window,
+ uw w, uw h)
+{
+ assert(window);
+ (void) window;
+ assert(glGetError() == GL_NO_ERROR);
+ gl_ortho_resize(&g_ortho, 0, w, 0, h, 0, 1);
+ assert(glGetError() == GL_NO_ERROR);
+ return true;
+}
+
+void window_sdl2_demo_unload (s_window_sdl2 *window)
+{
+ assert(window);
+ (void) window;
+ if (g_ortho.gl_shader_program) {
+ gl_ortho_clean(&g_ortho);
+ gl_font_clean(&g_font_courier_new);
+ gl_sprite_clean(&g_sprite_toaster);
+ gl_sprite_clean(&g_sprite_toast);
+ gl_font_clean(&g_font_flies);
+ gl_sprite_clean(&g_sprite_fly);
+ gl_sprite_clean(&g_sprite_dead_fly);
+ gl_sprite_clean(&g_sprite_earth);
+ }
+}
diff --git a/window/sdl2/demo/window_sdl2_demo.h b/window/sdl2/demo/window_sdl2_demo.h
new file mode 100644
index 0000000..3cccff5
--- /dev/null
+++ b/window/sdl2/demo/window_sdl2_demo.h
@@ -0,0 +1,23 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_SDL2_DEMO_H
+#define LIBKC3_WINDOW_SDL2_DEMO_H
+
+#include "../types.h"
+
+extern s_gl_font g_font_computer_modern;
+extern s_gl_font g_font_courier_new;
+
+extern s_gl_ortho g_ortho;
+
+#endif /* LIBKC3_WINDOW_SDL2_DEMO_H */
diff --git a/window/sdl2/disabled/mandelbrot.c b/window/sdl2/disabled/mandelbrot.c
new file mode 100644
index 0000000..e36e6c6
--- /dev/null
+++ b/window/sdl2/disabled/mandelbrot.c
@@ -0,0 +1,151 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "mandelbrot.h"
+
+GLuint g_mandelbrotComputeProgram = 0;
+GLuint g_mandelbrotComputeShader = 0;
+
+bool mandelbrot_load (s_sequence *seq, s_window_sdl2 *window)
+{
+ uw i;
+ uw star_count;
+ s_map *map;
+ (void) window;
+ if (! tag_map(&seq->tag, 5))
+ return false;
+ map = &seq->tag.data.map;
+ tag_init_sym_1(map->key + 0, "h");
+ tag_init_uw( map->value + 0, 0);
+ tag_init_sym_1(map->key + 1, "w");
+ tag_init_uw( map->value + 1, 0);
+ tag_init_sym_1(map->key + 2, "x");
+ tag_init_f64(map->value + 2, 0.0);
+ tag_init_sym_1(map->key + 3, "y");
+ tag_init_f64(map->value + 3, 0.0);
+ tag_init_sym_1(map->key + 4, "zoom");
+ tag_init_f64(map->value + 4, 1.0);
+ return true;
+}
+
+bool mandelbrot_render (s_sequence *seq, s_window_sdl2 *window,
+ void *context)
+{
+ uw *h;
+ s_map *map;
+ uw *w;
+ f64 *x;
+ f64 *y;
+ f64 *zoom;
+ assert(seq);
+ assert(window);
+ (void) context;
+ if (seq->tag.type != TAG_MAP) {
+ err_puts("mandelbrot_render: sequence tag is not a map");
+ assert(! "mandelbrot_render: sequence tag is not a map");
+ return false;
+ }
+ map = &seq->tag.data.map;
+ if (map->count != 5 ||
+ map->value[0].type != TAG_UW ||
+ map->value[1].type != TAG_UW ||
+ map->value[2].type != TAG_F64 ||
+ map->value[3].type != TAG_F64 ||
+ map->value[4].type != TAG_F64) {
+ err_puts("mandelbrot_render: invalid map");
+ assert(! "mandelbrot_render: invalid map");
+ return false;
+ }
+ h = &map->value[0].data.uw;
+ w = &map->value[1].data.uw;
+ x = &map->value[2].data.f64;
+ y = &map->value[3].data.f64;
+ zoom = &map->value[4].data.f64;
+ if (*w != window->w || *h != window->h) {
+ *w = window->w;
+ *h = window->h;
+ mandelbrot_texture_update(*w, *h);
+ }
+ // fullscreen texture
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glColor4f(1, 1, 1, 1);
+ glDisable(GL_BLEND);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+ glEnable(GL_TEXTURE_2D);
+ glBegin(GL_QUADS); {
+ glTexCoord2f(0, 1);
+ glVertex2f(-1, 1);
+ glTexCoord2f(0, 0);
+ glVertex2f(-1, -1);
+ glTexCoord2f(1, 0);
+ glVertex2f(1, -1);
+ glTexCoord2f(1, 1);
+ glVertex2f(1, 1);
+ } glEnd();
+ return true;
+}
+
+void mandelbrot_shader_init (void)
+{
+ const char* src =
+ "#version 430 core\n"
+ "layout (local_size_x = 16, local_size_y = 16) in;\n"
+ "layout (rgba32f, binding = 0) uniform image2D mandelbrotImage;\n"
+ "uniform int maxIterations;\n"
+ "uniform double zoom;\n"
+ "uniform dvec2 offset;\n"
+ "void main() {\n"
+ " ivec2 texelCoord = ivec2(gl_GlobalInvocationID.xy);\n"
+ " dvec2 c = (dvec2(texelCoord) /\n"
+ " double(imageSize(mandelbrotImage).y) - 0.5) *\n"
+ " zoom + offset;\n"
+ " dvec2 z = c;\n"
+ " int iterations = 0;\n"
+ " for (int i = 0; i < maxIterations; ++i) {\n"
+ " if (dot(z, z) > 4.0) {\n"
+ " break;\n"
+ " }\n"
+ " z = dvec2(z.x * z.x - z.y * z.y, 2.0 * z.x * z.y) + c;\n"
+ " iterations++;\n"
+ " }\n"
+ " vec4 color = vec4(float(iterations) / float(maxIterations));\n"
+ " imageStore(mandelbrotImage, texelCoord, color);\n"
+ "}\n";
+ g_mandelbrot_shader = glCreateShader(GL_COMPUTE_SHADER);
+ glShaderSource(g_mandelbrot_shader, 1, src, NULL);
+ glCompileShader(g_mandelbrot_shader);
+ g_mandelbrotShaderProgram = glCreateProgram();
+ glAttachShader(mandelbrotShaderProgram, g_mandelbrot_shader);
+ glLinkProgram(mandelbrotShaderProgram);
+ glUseProgram(mandelbrotShaderProgram);
+}
+
+void mandelbrot_texture_delete (void)
+{
+ glDeleteTextures(1, &g_mandelbrot_texture);
+}
+
+void mandelbrot_texture_init (void)
+{
+ glGenTextures(1, &g_mandelbrot_texture);
+}
+
+void mandelbrot_update_texture () {
+ glBindTexture(GL_TEXTURE_2D, mandelbrotImage);
+ glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, WIDTH, HEIGHT);
+ glBindImageTexture(0, mandelbrotImage, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
+}
diff --git a/window/sdl2/disabled/mandelbrot.h b/window/sdl2/disabled/mandelbrot.h
new file mode 100644
index 0000000..6ab1aff
--- /dev/null
+++ b/window/sdl2/disabled/mandelbrot.h
@@ -0,0 +1,22 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 MANDELBROT_H
+#define MANDELBROT_H
+
+#include "../types.h"
+
+bool mandelbrot_load (s_sequence *seq, s_window_sdl2 *window);
+bool mandelbrot_render (s_sequence *seq, s_window_sdl2 *window,
+ void *context);
+
+#endif /* MANDELBROT_H */
diff --git a/window/sdl2/disabled/sdl2_font.c b/window/sdl2/disabled/sdl2_font.c
new file mode 100644
index 0000000..d290efb
--- /dev/null
+++ b/window/sdl2/disabled/sdl2_font.c
@@ -0,0 +1,65 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "sdl2_font.h"
+
+void sdl2_font_clean (s_sdl2_font *font)
+{
+ assert(font);
+ if (font->ftgl_font)
+ ftglDestroyFont(font->ftgl_font);
+ str_clean(&font->path);
+ str_clean(&font->real_path);
+}
+
+s_sdl2_font * sdl2_font_init (s_sdl2_font *font, const s8 *path)
+{
+ assert(font);
+ assert(path);
+ str_init_copy_1(&font->path, path);
+ if (! file_search(&font->path, sym_1("r"), &font->real_path)) {
+ err_write_1("sdl2_font_init: file not found: ");
+ err_puts(path);
+ str_clean(&font->path);
+ return NULL;
+ }
+ assert(glGetError() == GL_NO_ERROR);
+ font->ftgl_font = ftglCreateTextureFont(font->real_path.ptr.ps8);
+ if (! font->ftgl_font) {
+ err_write_1("sdl2_font_init: error loading font: ");
+ err_puts(font->real_path.ptr.ps8);
+ str_clean(&font->path);
+ str_clean(&font->real_path);
+ return NULL;
+ }
+ assert(glGetError() == GL_NO_ERROR);
+ font->size = 0;
+ font->dpi = 72;
+ return font;
+}
+
+void sdl2_font_set_size (s_sdl2_font *font, u32 size, u32 dpi)
+{
+ assert(font);
+ assert(size);
+ ftglSetFontFaceSize(font->ftgl_font, size, dpi);
+ font->size = size;
+ font->dpi = dpi;
+}
+
+void sdl2_font_render_text (const s_sdl2_font *font, const s8 *p)
+{
+ assert(glGetError() == GL_NO_ERROR);
+ ftglRenderFont(font->ftgl_font, p, FTGL_RENDER_ALL);
+ assert(glGetError() == GL_NO_ERROR);
+}
diff --git a/window/sdl2/disabled/sdl2_font.h b/window/sdl2/disabled/sdl2_font.h
new file mode 100644
index 0000000..2e41777
--- /dev/null
+++ b/window/sdl2/disabled/sdl2_font.h
@@ -0,0 +1,29 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_SDL2_SDL2_FONT_H
+#define LIBKC3_WINDOW_SDL2_SDL2_FONT_H
+
+#include "types.h"
+
+/* Stack-allocation compatible functions, call sdl2_font_clean after
+ use. */
+void sdl2_font_clean (s_sdl2_font *font);
+s_sdl2_font * sdl2_font_init (s_sdl2_font *font, const s8 *path);
+
+/* Operators. */
+void sdl2_font_set_size (s_sdl2_font *font, u32 size, u32 dpi);
+
+/* Observers */
+void sdl2_font_render_text (const s_sdl2_font *font, const s8 *p);
+
+#endif /* LIBKC3_WINDOW_SDL2_SDL2_FONT_H */
diff --git a/window/sdl2/disabled/sdl2_sprite.c b/window/sdl2/disabled/sdl2_sprite.c
new file mode 100644
index 0000000..9568643
--- /dev/null
+++ b/window/sdl2/disabled/sdl2_sprite.c
@@ -0,0 +1,369 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "sdl2_sprite.h"
+
+void sdl2_sprite_bind (const s_sdl2_sprite *sprite, uw frame)
+{
+ assert(sprite);
+ assert(frame < sprite->frame_count);
+ frame %= sprite->frame_count;
+ assert(glGetError() == GL_NO_ERROR);
+ glBindTexture(GL_TEXTURE_2D, sprite->texture[frame]);
+ assert(glGetError() == GL_NO_ERROR);
+}
+
+void sdl2_sprite_clean (s_sdl2_sprite *sprite)
+{
+ assert(sprite);
+ str_clean(&sprite->path);
+ str_clean(&sprite->real_path);
+ glDeleteTextures(sprite->frame_count, sprite->texture);
+ free(sprite->texture);
+}
+
+static bool png_info_to_gl_info (s32 png_color_type,
+ s32 png_bit_depth,
+ GLenum *gl_format,
+ GLint *gl_internal_format,
+ GLenum *gl_type,
+ u8 *components)
+{
+ switch (png_bit_depth) {
+ case 8: *gl_type = GL_UNSIGNED_BYTE; break;
+ case 16: *gl_type = GL_UNSIGNED_SHORT; break;
+ default: *gl_type = 0; return false;
+ }
+ switch (png_color_type) {
+ case PNG_COLOR_TYPE_GRAY:
+ *components = 1;
+ *gl_format = GL_RED;
+ switch (png_bit_depth) {
+ case 8: *gl_internal_format = GL_RED; break;
+ case 16: *gl_internal_format = GL_RED; break;
+ default: *gl_internal_format = 0; return false;
+ }
+ break;
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ *components = 2;
+ *gl_format = GL_RG;
+ switch (png_bit_depth) {
+ case 8: *gl_internal_format = GL_RG; break;
+ case 16: *gl_internal_format = GL_RG; break;
+ default: *gl_internal_format = 0; return false;
+ }
+ break;
+ case PNG_COLOR_TYPE_RGB:
+ *components = 3;
+ *gl_format = GL_RGB;
+ switch (png_bit_depth) {
+ case 8: *gl_internal_format = GL_RGB; break;
+ case 16: *gl_internal_format = GL_RGB; break;
+ default: *gl_internal_format = 0; return false;
+ }
+ break;
+ case PNG_COLOR_TYPE_RGBA:
+ *components = 4;
+ *gl_format = GL_RGBA;
+ switch (png_bit_depth) {
+ case 8: *gl_internal_format = GL_RGBA8; break;
+ case 16: *gl_internal_format = GL_RGBA16; break;
+ default: *gl_internal_format = 0; return false;
+ }
+ break;
+ default:
+ *components = 0;
+ *gl_format = 0;
+ *gl_internal_format = 0;
+ return false;
+ }
+ return true;
+}
+
+s_sdl2_sprite * sdl2_sprite_init (s_sdl2_sprite *sprite,
+ const s8 *path,
+ uw dim_x, uw dim_y,
+ uw frame_count)
+{
+ u8 *data;
+ FILE *fp;
+ GLenum gl_format;
+ GLint gl_internal_format;
+ GLenum gl_type;
+ uw i;
+ s32 png_bit_depth;
+ s32 png_color_type;
+ u8 png_components;
+ png_bytep png_data;
+ u32 png_h;
+ u8 png_header[8]; // maximum size is 8
+ png_infop png_info;
+ uw png_pixel_size;
+ png_structp png_read;
+ png_bytep *png_row;
+ u32 png_w;
+ u8 *sprite_data;
+ uw sprite_stride;
+ uw x;
+ uw y;
+ uw v;
+ assert(sprite);
+ assert(path);
+ assert(dim_x);
+ assert(dim_y);
+ assert(glGetError() == GL_NO_ERROR);
+ sprite->frame_count = (frame_count > 0) ? frame_count :
+ (dim_x * dim_y);
+ str_init_copy_1(&sprite->path, path);
+ if (! file_search(&sprite->path, sym_1("r"), &sprite->real_path)) {
+ err_write_1("sdl2_sprite_init: file not found: ");
+ err_puts(path);
+ str_clean(&sprite->path);
+ return NULL;
+ }
+ fp = fopen(sprite->real_path.ptr.ps8, "rb");
+ if (! fp) {
+ err_write_1("sdl2_sprite_init: fopen: ");
+ err_puts(sprite->real_path.ptr.ps8);
+ str_clean(&sprite->path);
+ str_clean(&sprite->real_path);
+ return NULL;
+ }
+ if (fread(png_header, 1, sizeof(png_header), fp) !=
+ sizeof(png_header)) {
+ err_write_1("sdl2_sprite_init: fread: ");
+ err_puts(sprite->real_path.ptr.ps8);
+ fclose(fp);
+ str_clean(&sprite->path);
+ str_clean(&sprite->real_path);
+ return NULL;
+ }
+ if (png_sig_cmp(png_header, 0, sizeof(png_header))) {
+ err_write_1("sdl2_sprite_init: not a png: ");
+ err_puts(sprite->real_path.ptr.ps8);
+ fclose(fp);
+ str_clean(&sprite->path);
+ str_clean(&sprite->real_path);
+ return NULL;
+ }
+ png_read = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL,
+ NULL);
+ if (! png_read) {
+ err_write_1("sdl2_sprite_init: png_create_read_struct: ");
+ err_puts(sprite->real_path.ptr.ps8);
+ fclose(fp);
+ str_clean(&sprite->path);
+ str_clean(&sprite->real_path);
+ return NULL;
+ }
+ png_info = png_create_info_struct(png_read);
+ if (! png_info) {
+ err_write_1("sdl2_sprite_init: png_create_info_struct: ");
+ err_puts(sprite->real_path.ptr.ps8);
+ png_destroy_read_struct(&png_read, NULL, NULL);
+ fclose(fp);
+ str_clean(&sprite->path);
+ str_clean(&sprite->real_path);
+ return NULL;
+ }
+ gl_internal_format = 0;
+ gl_format = 0;
+ gl_type = 0;
+ png_components = 0;
+ if (setjmp(png_jmpbuf(png_read))) {
+ png_destroy_read_struct(&png_read, &png_info, NULL);
+ fclose(fp);
+ str_clean(&sprite->path);
+ str_clean(&sprite->real_path);
+ return NULL;
+ }
+ png_set_sig_bytes(png_read, sizeof(png_header));
+ png_init_io(png_read, fp);
+ png_read_info(png_read, png_info);
+ png_get_IHDR(png_read, png_info, &png_w, &png_h,
+ &png_bit_depth, &png_color_type,
+ NULL, NULL, NULL);
+ if (png_color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_palette_to_rgb(png_read);
+ if (! png_info_to_gl_info(png_color_type, png_bit_depth, &gl_format,
+ &gl_internal_format, &gl_type,
+ &png_components)) {
+ if (! gl_format || ! png_components) {
+ err_write_1("sdl2_sprite_init: unknown PNG color type ");
+ err_inspect_s32(&png_color_type);
+ err_write_1(": ");
+ err_puts(sprite->real_path.ptr.ps8);
+ }
+ if (! gl_internal_format) {
+ err_write_1("sdl2_sprite_init: unknown OpenGL internal format: ");
+ err_puts(sprite->real_path.ptr.ps8);
+ }
+ if (! gl_type) {
+ err_write_1("sdl2_sprite_init: unknown OpenGL type: ");
+ err_puts(sprite->real_path.ptr.ps8);
+ }
+ png_destroy_read_struct(&png_read, &png_info, NULL);
+ fclose(fp);
+ str_clean(&sprite->path);
+ str_clean(&sprite->real_path);
+ return NULL;
+ }
+ png_pixel_size = (png_bit_depth / 8) * png_components;
+ if (! png_pixel_size)
+ png_error(png_read, "unknown png pixel size");
+ if (png_h > PNG_SIZE_MAX / (png_w * png_pixel_size))
+ png_error(png_read, "image_data buffer would be too large");
+ png_data = png_malloc(png_read, png_h * png_w * png_pixel_size);
+ png_row = png_malloc(png_read, png_h * sizeof(png_bytep));
+ i = 0;
+ while (i < png_h) {
+ png_row[i] = png_data + i * png_w * png_pixel_size;
+ i++;
+ }
+ if (png_bit_depth < 8)
+ png_set_packing(png_read);
+ png_read_image(png_read, png_row);
+ png_destroy_read_struct(&png_read, &png_info, NULL);
+ fclose(fp);
+ sprite->total_w = png_w;
+ sprite->total_h = png_h;
+ sprite->dim_x = dim_x;
+ sprite->dim_y = dim_y;
+ sprite->w = sprite->total_w / dim_x;
+ sprite->h = sprite->total_h / dim_y;
+ sprite->texture = calloc(sprite->frame_count, sizeof(GLuint));
+ if (! sprite->texture) {
+ err_puts("sdl2_sprite_init: sprite->texture:"
+ " failed to allocate memory");
+ str_clean(&sprite->path);
+ str_clean(&sprite->real_path);
+ return NULL;
+ }
+ glGenTextures(sprite->frame_count, sprite->texture);
+ GLenum gl_error = glGetError();
+ if (gl_error != GL_NO_ERROR) {
+ err_write_1("sdl2_sprite_init: ");
+ err_inspect_str(&sprite->real_path);
+ err_write_1(": glGenTextures: ");
+ err_puts((const s8 *) gluErrorString(gl_error));
+ free(sprite->texture);
+ str_clean(&sprite->path);
+ str_clean(&sprite->real_path);
+ return NULL;
+ }
+ sprite_stride = sprite->w * png_pixel_size;
+ data = malloc(sprite->h * sprite_stride);
+ if (! data) {
+ err_write_1("sdl2_sprite_init: failed to allocate memory: ");
+ err_puts(sprite->real_path.ptr.ps8);
+ free(sprite->texture);
+ str_clean(&sprite->path);
+ str_clean(&sprite->real_path);
+ return NULL;
+ }
+ i = 0;
+ y = 0;
+ while (i < sprite->frame_count && y < dim_y) {
+ x = 0;
+ while (i < sprite->frame_count && x < dim_x) {
+ sprite_data = data + sprite_stride * sprite->h;
+ v = 0;
+ while (v < sprite->h) {
+ sprite_data -= sprite_stride;
+ memcpy(sprite_data,
+ png_row[y * sprite->h + v] + x * sprite_stride,
+ sprite_stride);
+ v++;
+ }
+ glBindTexture(GL_TEXTURE_2D, sprite->texture[i]);
+ gl_error = glGetError();
+ if (gl_error != GL_NO_ERROR) {
+ err_write_1("sdl2_sprite_init: ");
+ err_inspect_str(&sprite->real_path);
+ err_write_1(": glBindTexture: ");
+ err_puts((const s8 *) gluErrorString(gl_error));
+ return NULL;
+ }
+ 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_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gl_error = glGetError();
+ if (gl_error != GL_NO_ERROR) {
+ err_write_1("sdl2_sprite_init: ");
+ err_inspect_str(&sprite->real_path);
+ err_write_1(": glTexParameteri: ");
+ err_puts((const s8 *) gluErrorString(gl_error));
+ return NULL;
+ }
+ glTexImage2D(GL_TEXTURE_2D, 0, gl_format, sprite->w, sprite->h,
+ 0, gl_format, gl_type, data);
+ //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sprite->w, sprite->h,
+ // 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ gl_error = glGetError();
+ if (gl_error != GL_NO_ERROR) {
+ err_write_1("sdl2_sprite_init: ");
+ err_inspect_str(&sprite->real_path);
+ err_write_1(": glTexImage2D: ");
+ err_puts((const s8 *) gluErrorString(gl_error));
+ return NULL;
+ }
+ glGenerateMipmap(GL_TEXTURE_2D);
+ assert(glGetError() == GL_NO_ERROR);
+ i++;
+ x++;
+ }
+ y++;
+ }
+ glBindTexture(GL_TEXTURE_2D, 0);
+ free(data);
+ free(png_data);
+ free(png_row);
+ return sprite;
+}
+
+void sdl2_sprite_render (const s_sdl2_sprite *sprite, uw frame)
+{
+ assert(sprite);
+ assert(frame < sprite->frame_count);
+ frame %= sprite->frame_count;
+ glColor4f(1, 1, 1, 1);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_CULL_FACE);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, sprite->texture[frame]);
+ glBegin(GL_QUADS); {
+ glTexCoord2f(0, 1);
+ glVertex2d(0, sprite->h);
+ glTexCoord2f(0, 0);
+ glVertex2i(0, 0);
+ glTexCoord2f(1, 0);
+ glVertex2i(sprite->w, 0);
+ glTexCoord2f(1, 1);
+ glVertex2d(sprite->w, sprite->h);
+ } glEnd();
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDisable(GL_TEXTURE_2D);
+ /*
+ glBegin(GL_LINE_LOOP); {
+ glVertex2d(0, sprite->h);
+ glVertex2i(0, 0);
+ glVertex2i(sprite->w, 0);
+ glVertex2d(sprite->w, sprite->h);
+ } glEnd();
+ */
+}
diff --git a/window/sdl2/disabled/sdl2_sprite.h b/window/sdl2/disabled/sdl2_sprite.h
new file mode 100644
index 0000000..720d3f9
--- /dev/null
+++ b/window/sdl2/disabled/sdl2_sprite.h
@@ -0,0 +1,29 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 SDL2_SPRITE_H
+#define SDL2_SPRITE_H
+
+#include "types.h"
+
+/* stack allocation compatible functions */
+void sdl2_sprite_clean (s_sdl2_sprite *sprite);
+s_sdl2_sprite * sdl2_sprite_init (s_sdl2_sprite *sprite,
+ const s8 *path,
+ uw dim_x, uw dim_y,
+ uw frame_count);
+
+/* operations */
+void sdl2_sprite_bind (const s_sdl2_sprite *sprite, uw frame);
+void sdl2_sprite_render (const s_sdl2_sprite *sprite, uw frame);
+
+#endif /* CAIRO_SPRITE_H */
diff --git a/window/sdl2/dmat3.h b/window/sdl2/dmat3.h
new file mode 100644
index 0000000..2e3a3c4
--- /dev/null
+++ b/window/sdl2/dmat3.h
@@ -0,0 +1,35 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 DMAT3_H
+#define DMAT3_H
+
+#include "types.h"
+
+/* Stack-allocation compatible functions. */
+s_dmat3 * dmat3_init_copy (s_dmat3 *m, const s_dmat3 *src);
+s_dmat3 * dmat3_init_identity (s_dmat3 *m);
+s_dmat3 * dmat3_init_matrix_mult (s_dmat3 *m, const s_dmat3 *a,
+ const s_dmat3 *b);
+
+/* Heap-allocation functions, call dmat3_delete after use. */
+void dmat3_delete (s_dmat3 *m);
+s_dmat3 * dmat3_new_copy (const s_dmat3 *src);
+s_dmat3 * dmat3_new_identity (void);
+s_dmat3 * dmat3_new_matrix_mult (const s_dmat3 *a, const s_dmat3 *b);
+
+/* Operators. */
+s_dmat3 * dmat3_rotate (s_dmat3 *m, f64 rad);
+s_dmat3 * dmat3_scale (s_dmat3 *m, f64 x, f64 y);
+s_dmat3 * dmat3_translate (s_dmat3 *m, f64 x, f64 y);
+
+#endif /* DMAT3_H */
diff --git a/window/sdl2/dmat4.c b/window/sdl2/dmat4.c
new file mode 100644
index 0000000..674f3f4
--- /dev/null
+++ b/window/sdl2/dmat4.c
@@ -0,0 +1,276 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "dmat4.h"
+#include "dvec3.h"
+
+sw dmat4_buf_inspect (s_buf *buf, const s_dmat4 *matrix)
+{
+ u8 i;
+ u8 j;
+ sw r;
+ sw result = 0;
+ assert(buf);
+ assert(matrix);
+ const f64 *m;
+ if ((r = buf_write_1(buf, "(F64) {")) < 0)
+ return r;
+ result += r;
+ m = &matrix->xx;
+ i = 0;
+ while (i < 4) {
+ j = 0;
+ while (j < 4) {
+ if ((r = buf_inspect_f64(buf, m + j * 4 + i)) < 0)
+ return r;
+ result += r;
+ if (i < 3 || j < 3) {
+ if ((r = buf_write_1(buf, ",")) < 0)
+ return r;
+ result += r;
+ if (j < 3) {
+ if ((r = buf_write_1(buf, " ")) < 0)
+ return r;
+ result += r;
+ }
+ }
+ j++;
+ }
+ if (i < 3) {
+ if ((r = buf_write_1(buf, "\n ")) < 0)
+ return r;
+ result += r;
+ }
+ i++;
+ }
+ if ((r = buf_write_1(buf, "}\n")) < 0)
+ return r;
+ result += r;
+ return result;
+}
+
+s_dmat4 * dmat4_init_copy (s_dmat4 *m, const s_dmat4 *src)
+{
+ assert(m);
+ assert(src);
+ *m = *src;
+ return m;
+}
+
+s_dmat4 * dmat4_init_product (s_dmat4 *m, const s_dmat4 *a,
+ const s_dmat4 *b)
+{
+ assert(m);
+ assert(a);
+ assert(b);
+ m->xx = a->xx * b->xx + a->xy * b->yx + a->xz * b->zx + a->xt * b->tx;
+ m->xy = a->xx * b->xy + a->xy * b->yy + a->xz * b->zy + a->xt * b->ty;
+ m->xz = a->xx * b->xz + a->xy * b->yz + a->xz * b->zz + a->xt * b->tz;
+ m->xt = a->xx * b->xt + a->xy * b->yt + a->xz * b->zt + a->xt * b->tt;
+ m->yx = a->yx * b->xx + a->yy * b->yx + a->yz * b->zx + a->yt * b->tx;
+ m->yy = a->yx * b->xy + a->yy * b->yy + a->yz * b->zy + a->yt * b->ty;
+ m->yz = a->yx * b->xz + a->yy * b->yz + a->yz * b->zz + a->yt * b->tz;
+ m->yt = a->yx * b->xt + a->yy * b->yt + a->yz * b->zt + a->yt * b->tt;
+ m->zx = a->zx * b->xx + a->zy * b->yx + a->zz * b->zx + a->zt * b->tx;
+ m->zy = a->zx * b->xy + a->zy * b->yy + a->zz * b->zy + a->zt * b->ty;
+ m->zz = a->zx * b->xz + a->zy * b->yz + a->zz * b->zz + a->zt * b->tz;
+ m->zt = a->zx * b->xt + a->zy * b->yt + a->zz * b->zt + a->zt * b->tt;
+ m->tx = a->tx * b->xx + a->ty * b->yx + a->tz * b->zx + a->tt * b->tx;
+ m->ty = a->tx * b->xy + a->ty * b->yy + a->tz * b->zy + a->tt * b->ty;
+ m->tz = a->tx * b->xz + a->ty * b->yz + a->tz * b->zz + a->tt * b->tz;
+ m->tt = a->tx * b->xt + a->ty * b->yt + a->tz * b->zt + a->tt * b->tt;
+ return m;
+}
+
+s_dmat4 * dmat4_init_identity (s_dmat4 *m)
+{
+ assert(m);
+ m->xx = 1.0; m->xy = 0.0; m->xz = 0.0; m->xt = 0.0;
+ m->yx = 0.0; m->yy = 1.0; m->yz = 0.0; m->yt = 0.0;
+ m->zx = 0.0; m->zy = 0.0; m->zz = 1.0; m->zt = 0.0;
+ m->tx = 0.0; m->ty = 0.0; m->tz = 0.0; m->tt = 1.0;
+ return m;
+}
+
+s_dmat4 * dmat4_init_scale (s_dmat4 *m, f64 x, f64 y, f64 z)
+{
+ assert(m);
+ m->xx = x; m->xy = 0.0; m->xz = 0.0; m->xt = 0.0;
+ m->yx = 0.0; m->yy = y; m->yz = 0.0; m->yt = 0.0;
+ m->zx = 0.0; m->zy = 0.0; m->zz = z; m->zt = 0.0;
+ m->tx = 0.0; m->ty = 0.0; m->tz = 0.0; m->tt = 1.0;
+ return m;
+}
+
+s_dmat4 * dmat4_init_zero (s_dmat4 *m)
+{
+ assert(m);
+ m->xx = 0.0; m->xy = 0.0; m->xz = 0.0; m->xt = 0.0;
+ m->yx = 0.0; m->yy = 0.0; m->yz = 0.0; m->yt = 0.0;
+ m->zx = 0.0; m->zy = 0.0; m->zz = 0.0; m->zt = 0.0;
+ m->tx = 0.0; m->ty = 0.0; m->tz = 0.0; m->tt = 0.0;
+ return m;
+}
+
+void dmat4_delete (s_dmat4 *m)
+{
+ free(m);
+}
+
+s_dmat4 * dmat4_new_copy (const s_dmat4 *src)
+{
+ s_dmat4 *m;
+ m = calloc(1, sizeof(s_dmat4));
+ if (! m) {
+ err_puts("dmat4_new: failed to allocate memory");
+ return NULL;
+ }
+ *m = *src;
+ return m;
+}
+
+s_dmat4 * dmat4_new_product (const s_dmat4 *a, const s_dmat4 *b)
+{
+ s_dmat4 *m;
+ assert(a);
+ assert(b);
+ m = calloc(1, sizeof(s_dmat4));
+ if (! m) {
+ err_puts("dmat4_new: failed to allocate memory");
+ return NULL;
+ }
+ dmat4_init_product(m, a, b);
+ return m;
+}
+
+s_dmat4 * dmat4_new_zero (void)
+{
+ s_dmat4 *m;
+ m = calloc(1, sizeof(s_dmat4));
+ if (! m) {
+ err_puts("dmat4_new: failed to allocate memory");
+ return NULL;
+ }
+ dmat4_init_zero(m);
+ return m;
+}
+
+s_dmat4 * dmat4_ortho (s_dmat4 *m, f64 x1, f64 x2, f64 y1, f64 y2,
+ f64 clip_z_near, f64 clip_z_far)
+{
+ f64 dx;
+ f64 dy;
+ f64 dz;
+ s_dmat4 ortho;
+ assert(m);
+ dx = x2 - x1;
+ dy = y2 - y1;
+ dz = clip_z_far - clip_z_near;
+ dmat4_init_zero(&ortho);
+ ortho.xx = 2.0 / dx;
+ ortho.yy = 2.0 / dy;
+ ortho.zz = -2.0 / dz;
+ ortho.tx = - (x1 + x2) / dx;
+ ortho.ty = - (y1 + y2) / dy;
+ ortho.tz = - (clip_z_near + clip_z_far) / dz;
+ ortho.tt = 1.0;
+ dmat4_product(&ortho, m);
+ *m = ortho;
+ return m;
+}
+
+s_dmat4 * dmat4_perspective (s_dmat4 *m, f64 fov_y, f64 aspect_ratio,
+ f64 z_near, f64 z_far)
+{
+ f64 dz;
+ s_dmat4 perspective;
+ f64 f;
+ f64 fov_y_2;
+ fov_y_2 = fov_y / 2.0;
+ f = cos(fov_y_2) / sin(fov_y_2);
+ dz = z_near - z_far;
+ dmat4_init_zero(&perspective);
+ perspective.xx = f / aspect_ratio;
+ perspective.yy = f;
+ perspective.zz = (z_near + z_far) / dz;
+ perspective.zt = -1.0;
+ perspective.tz = 2.0 * z_near * z_far / dz;
+ dmat4_product(&perspective, m);
+ *m = perspective;
+ return m;
+}
+
+s_dmat4 * dmat4_product (s_dmat4 *m, const s_dmat4 *a)
+{
+ s_dmat4 tmp;
+ dmat4_init_product(&tmp, m, a);
+ *m = tmp;
+ return m;
+}
+
+s_dmat4 * dmat4_rotate_axis (s_dmat4 *m, f64 rad,
+ const s_dvec3 *axis)
+{
+ s_dvec3 a;
+ f64 angle;
+ f64 one_minus_x;
+ f64 x;
+ f64 y;
+ dvec3_init_normalize(&a, axis);
+ angle = -rad;
+ x = cos(angle);
+ one_minus_x = 1.0 - x;
+ y = sin(angle);
+ s_dmat4 r = { x + a.x * a.x * one_minus_x,
+ a.x * a.y * one_minus_x - a.z * y,
+ a.x * a.z * one_minus_x + a.y * y,
+ 0.0,
+ a.x * a.y * one_minus_x + a.z * y,
+ x + a.y * a.y * one_minus_x,
+ a.y * a.z * one_minus_x - a.x * y,
+ 0.0,
+ a.x * a.z * one_minus_x - a.y * y,
+ a.y * a.z * one_minus_x + a.x * y,
+ x + a.z * a.z * one_minus_x,
+ 0.0,
+ 0.0, 0.0, 0.0, 1.0 };
+ dmat4_product(&r, m);
+ *m = r;
+ return m;
+}
+
+s_dmat4 * dmat4_scale (s_dmat4 *m, f64 x, f64 y, f64 z)
+{
+ s_dmat4 s;
+ dmat4_init_zero(&s);
+ s.xx = x;
+ s.yy = y;
+ s.zz = z;
+ s.tt = 1.0;
+ dmat4_product(&s, m);
+ *m = s;
+ return m;
+}
+
+s_dmat4 * dmat4_translate (s_dmat4 *m, f64 x, f64 y, f64 z)
+{
+ s_dmat4 s;
+ dmat4_init_identity(&s);
+ s.tx = x;
+ s.ty = y;
+ s.tz = z;
+ dmat4_product(&s, m);
+ *m = s;
+ return m;
+}
diff --git a/window/sdl2/dmat4.h b/window/sdl2/dmat4.h
new file mode 100644
index 0000000..98659cf
--- /dev/null
+++ b/window/sdl2/dmat4.h
@@ -0,0 +1,43 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 DMAT4_H
+#define DMAT4_H
+
+#include "types.h"
+
+/* Stack-allocation compatible functions. */
+s_dmat4 * dmat4_init_copy (s_dmat4 *m, const s_dmat4 *src);
+s_dmat4 * dmat4_init_identity (s_dmat4 *m);
+s_dmat4 * dmat4_init_product (s_dmat4 *m, const s_dmat4 *a,
+ const s_dmat4 *b);
+s_dmat4 * dmat4_init_zero (s_dmat4 *m);
+
+/* Heap-allocation functions, call dmat4_delete after use. */
+void dmat4_delete (s_dmat4 *m);
+s_dmat4 * dmat4_new_copy (const s_dmat4 *src);
+s_dmat4 * dmat4_new_identity (void);
+s_dmat4 * dmat4_new_matrix_mult (const s_dmat4 *a, const s_dmat4 *b);
+s_dmat4 * dmat4_new_zero (void);
+
+/* Operators. */
+s_dmat4 * dmat4_ortho (s_dmat4 *m, f64 x1, f64 x2, f64 y1, f64 y2,
+ f64 clip_z_near, f64 clip_z_far);
+s_dmat4 * dmat4_perspective (s_dmat4 *m, f64 fov_y, f64 aspect_ratio,
+ f64 clip_z_near, f64 clip_z_far);
+s_dmat4 * dmat4_product (s_dmat4 *m, const s_dmat4 *a);
+s_dmat4 * dmat4_rotate_axis (s_dmat4 *m, f64 rad,
+ const s_dvec3 *axis);
+s_dmat4 * dmat4_scale (s_dmat4 *m, f64 x, f64 y, f64 z);
+s_dmat4 * dmat4_translate (s_dmat4 *m, f64 x, f64 y, f64 z);
+
+#endif /* DMAT4_H */
diff --git a/window/sdl2/dvec2.c b/window/sdl2/dvec2.c
new file mode 100644
index 0000000..bfefca2
--- /dev/null
+++ b/window/sdl2/dvec2.c
@@ -0,0 +1,92 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "dvec2.h"
+
+s_dvec2 * dvec2_init (s_dvec2 *p, f64 x, f64 y)
+{
+ assert(p);
+ p->x = x;
+ p->y = y;
+ return p;
+}
+
+s_dvec2 * dvec2_init_copy (s_dvec2 *p, const s_dvec2 *src)
+{
+ assert(p);
+ assert(src);
+ p->x = src->x;
+ p->y = src->y;
+ return p;
+}
+
+s_dvec2 * dvec2_init_product (s_dvec2 *p, const s_dmat3 *m,
+ const s_dvec2 *s)
+{
+ assert(p);
+ assert(m);
+ assert(s);
+ p->x = s->x * m->xx + s->y * m->xy + m->xz;
+ p->y = s->x * m->yx + s->y * m->yy + m->yz;
+ return p;
+}
+
+s_dvec2 * dvec2_init_zero (s_dvec2 *p)
+{
+ assert(p);
+ p->x = 0.0;
+ p->y = 0.0;
+ return p;
+}
+
+void dvec2_delete (s_dvec2 *p)
+{
+ free(p);
+}
+
+s_dvec2 * dvec2_new (f64 x, f64 y)
+{
+ s_dvec2 *p;
+ p = calloc(1, sizeof(s_dvec2));
+ if (! p) {
+ err_puts("dvec2_new: failed to allocate memory");
+ return NULL;
+ }
+ dvec2_init(p, x, y);
+ return p;
+}
+
+s_dvec2 * dvec2_new_copy (const s_dvec2 *src)
+{
+ s_dvec2 *p;
+ p = calloc(1, sizeof(s_dvec2));
+ if (! p) {
+ err_puts("dvec2_new: failed to allocate memory");
+ return NULL;
+ }
+ dvec2_init_copy(p, src);
+ return p;
+}
+
+s_dvec2 * dvec2_new_zero (void)
+{
+ s_dvec2 *p;
+ p = calloc(1, sizeof(s_dvec2));
+ if (! p) {
+ err_puts("dvec2_new: failed to allocate memory");
+ return NULL;
+ }
+ dvec2_init_zero(p);
+ return p;
+}
diff --git a/window/sdl2/dvec2.h b/window/sdl2/dvec2.h
new file mode 100644
index 0000000..13c5e85
--- /dev/null
+++ b/window/sdl2/dvec2.h
@@ -0,0 +1,32 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 DVEC2_H
+#define DVEC2_H
+
+#include "types.h"
+
+/* Stack-allocation compatible functions. */
+s_dvec2 * dvec2_init (s_dvec2 *p, f64 x, f64 y);
+s_dvec2 * dvec2_init_copy (s_dvec2 *p, const s_dvec2 *src);
+s_dvec2 * dvec2_init_product (s_dvec2 *p, const s_dmat3 *m,
+ const s_dvec2 *s);
+s_dvec2 * dvec2_init_zero (s_dvec2 *p);
+
+/* Heap-allocation functions, call dvec2_delete after use. */
+void dvec2_delete (s_dvec2 *p);
+s_dvec2 * dvec2_new (f64 x, f64 y);
+s_dvec2 * dvec2_new_copy (const s_dvec2 *src);
+s_dvec2 * dvec2_new_product (const s_dmat3 *m, const s_dvec2 *s);
+s_dvec2 * dvec2_new_zero (void);
+
+#endif /* DVEC2_H */
diff --git a/window/sdl2/dvec3.c b/window/sdl2/dvec3.c
new file mode 100644
index 0000000..15be8f5
--- /dev/null
+++ b/window/sdl2/dvec3.c
@@ -0,0 +1,147 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "dvec3.h"
+
+s_dvec3 * dvec3_init (s_dvec3 *p, f64 x, f64 y, f64 z)
+{
+ assert(p);
+ p->x = x;
+ p->y = y;
+ p->z = z;
+ return p;
+}
+
+s_dvec3 * dvec3_init_copy (s_dvec3 *p, const s_dvec3 *src)
+{
+ assert(p);
+ assert(src);
+ p->x = src->x;
+ p->y = src->y;
+ p->z = src->z;
+ return p;
+}
+
+s_dvec3 * dvec3_init_normalize (s_dvec3 *p, const s_dvec3 *src)
+{
+ f64 r;
+ assert(p);
+ assert(src);
+ r = 1.0 / dvec3_norm(src);
+ p->x = src->x * r;
+ p->y = src->y * r;
+ p->z = src->z * r;
+ return p;
+}
+
+s_dvec3 * dvec3_init_product (s_dvec3 *p, const s_dmat4 *m,
+ const s_dvec3 *s)
+{
+ assert(p);
+ assert(m);
+ assert(s);
+ p->x = s->x * m->xx + s->y * m->xy + s->z * m->xz + m->xt;
+ p->y = s->x * m->yx + s->y * m->yy + s->z * m->yz + m->yt;
+ p->z = s->x * m->zx + s->y * m->zy + s->z * m->zz + m->zt;
+ return p;
+}
+
+s_dvec3 * dvec3_init_zero (s_dvec3 *p)
+{
+ assert(p);
+ p->x = 0.0;
+ p->y = 0.0;
+ p->z = 0.0;
+ return p;
+}
+
+void dvec3_delete (s_dvec3 *p)
+{
+ free(p);
+}
+
+s_dvec3 * dvec3_new (f64 x, f64 y, f64 z)
+{
+ s_dvec3 *p;
+ p = calloc(1, sizeof(s_dvec3));
+ if (! p) {
+ err_puts("dvec3_new: failed to allocate memory");
+ return NULL;
+ }
+ dvec3_init(p, x, y, z);
+ return p;
+}
+
+s_dvec3 * dvec3_new_copy (const s_dvec3 *src)
+{
+ s_dvec3 *p;
+ p = calloc(1, sizeof(s_dvec3));
+ if (! p) {
+ err_puts("dvec3_new: failed to allocate memory");
+ return NULL;
+ }
+ dvec3_init_copy(p, src);
+ return p;
+}
+
+s_dvec3 * dvec3_new_product (const s_dmat4 *m, const s_dvec3 *s)
+{
+ s_dvec3 *p;
+ assert(m);
+ assert(s);
+ p = calloc(1, sizeof(s_dvec3));
+ if (! p) {
+ err_puts("dvec3_new: failed to allocate memory");
+ return NULL;
+ }
+ dvec3_init_product(p, m, s);
+ return p;
+}
+
+s_dvec3 * dvec3_new_zero (void)
+{
+ s_dvec3 *p;
+ p = calloc(1, sizeof(s_dvec3));
+ if (! p) {
+ err_puts("dvec3_new: failed to allocate memory");
+ return NULL;
+ }
+ dvec3_init_zero(p);
+ return p;
+}
+
+f64 dvec3_norm (const s_dvec3 *p)
+{
+ assert(p);
+ return sqrt(p->x * p->x + p->y * p->y + p->z * p->z);
+}
+
+void dvec3_normalize (s_dvec3 *p)
+{
+ f64 inv_norm;
+ assert(p);
+ inv_norm = 1.0 / dvec3_norm(p);
+ p->x *= inv_norm;
+ p->y *= inv_norm;
+ p->z *= inv_norm;
+}
+
+void dvec3_transform (s_dvec3 *p, const s_dmat4 *matrix)
+{
+ s_dvec3 tmp;
+ assert(p);
+ assert(matrix);
+ dvec3_init_product(&tmp, matrix, p);
+ *p = tmp;
+}
diff --git a/window/sdl2/dvec3.h b/window/sdl2/dvec3.h
new file mode 100644
index 0000000..13f3d30
--- /dev/null
+++ b/window/sdl2/dvec3.h
@@ -0,0 +1,41 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 DVEC3_H
+#define DVEC3_H
+
+#include "types.h"
+
+/* Stack-allocation compatible functions. */
+s_dvec3 * dvec3_init (s_dvec3 *p, f64 x, f64 y, f64 z);
+s_dvec3 * dvec3_init_copy (s_dvec3 *p, const s_dvec3 *src);
+s_dvec3 * dvec3_init_normalize (s_dvec3 *p, const s_dvec3 *src);
+s_dvec3 * dvec3_init_product (s_dvec3 *p, const s_dmat4 *m,
+ const s_dvec3 *s);
+s_dvec3 * dvec3_init_zero (s_dvec3 *p);
+
+/* Heap-allocation functions, call dvec3_delete after use. */
+void dvec3_delete (s_dvec3 *p);
+s_dvec3 * dvec3_new (f64 x, f64 y, f64 z);
+s_dvec3 * dvec3_new_copy (const s_dvec3 *src);
+s_dvec3 * dvec3_new_product (const s_dmat4 *m,
+ const s_dvec3 *s);
+s_dvec3 * dvec3_new_zero (void);
+
+/* Operators. */
+void dvec3_normalize (s_dvec3 *p);
+void dvec3_transform (s_dvec3 *p, const s_dmat4 *matrix);
+
+/* Observers. */
+f64 dvec3_norm (const s_dvec3 *p);
+
+#endif /* DVEC3_H */
diff --git a/window/sdl2/gl_camera.c b/window/sdl2/gl_camera.c
new file mode 100644
index 0000000..e85b1bd
--- /dev/null
+++ b/window/sdl2/gl_camera.c
@@ -0,0 +1,321 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "gl_camera.h"
+#include "mat4.h"
+
+static const char * g_gl_camera_vertex_shader_src =
+ "#version 330 core\n"
+ "layout (location = 0) in vec3 iPos;\n"
+ "layout (location = 1) in vec3 iNormal;\n"
+ "layout (location = 2) in vec2 iTexCoord;\n"
+ "out vec3 ioNormal;\n"
+ "out vec3 ioPos;\n"
+ "out vec2 ioTexCoord;\n"
+ "uniform mat4 uProjectionMatrix;\n"
+ "uniform mat4 uViewMatrix;\n"
+ "uniform mat4 uModelMatrix;\n"
+ "\n"
+ "void main() {\n"
+ " gl_Position = vec4(uProjectionMatrix * uViewMatrix *\n"
+ " uModelMatrix * vec4(iPos, 1.0));\n"
+ " ioNormal = vec3(uViewMatrix * uModelMatrix * vec4(iNormal, 1.0));\n"
+ " ioPos = (uViewMatrix * uModelMatrix * vec4(iPos, 1.0)).xyz;\n"
+ " ioTexCoord = iTexCoord;\n"
+ "}\n";
+
+static const char * g_gl_camera_fragment_shader_src =
+ "#version 330 core\n"
+ "const float PI = 3.141592653;\n"
+ "in vec3 ioNormal;\n"
+ "in vec3 ioPos;\n"
+ "in vec2 ioTexCoord;\n"
+ "out vec4 oColor;\n"
+ "uniform bool uEnableTex2D;\n"
+ "uniform sampler2D uTex2D;\n"
+ "uniform int uLightCount;\n"
+ "uniform vec3 uLightPos[16]; // Light position in cam. coords.\n"
+ "uniform vec3 uLightColor[16];\n"
+ "uniform struct MaterialInfo {\n"
+ " float Rough; // Roughness\n"
+ " bool Metal; // Metallic (true) or dielectric (false)\n"
+ " vec4 Color; // Diffuse color for dielectrics, f0 for metallic\n"
+ "} uMaterial;\n"
+ "float ggxDistribution (float nDotH) {\n"
+ " float alpha2 = uMaterial.Rough * uMaterial.Rough *\n"
+ " uMaterial.Rough * uMaterial.Rough;\n"
+ " float d = (nDotH * nDotH) * (alpha2 - 1) + 1;\n"
+ " return alpha2 / (PI * d * d);\n"
+ "}\n"
+ "float geomSmith( float dotProd ) {\n"
+ " float k = (uMaterial.Rough + 1.0) * (uMaterial.Rough + 1.0) / 8.0;\n"
+ " float denom = dotProd * (1 - k) + k;\n"
+ " return 1.0 / denom;\n"
+ "}\n"
+ "vec4 schlickFresnel( float lDotH ) {\n"
+ " vec4 f0 = vec4(0.04, 0.04, 0.04, 1.0);\n"
+ " if( uMaterial.Metal ) {\n"
+ " f0 = uMaterial.Color;\n"
+ " }\n"
+ " return f0 + (1 - f0) * pow(1.0 - lDotH, 5);\n"
+ "}\n"
+ "vec4 microfacetModel (int lightIdx, vec3 pos, vec3 n, vec4 color) {\n"
+ " vec4 diffuseBrdf = vec4(0.0, 0.0, 0.0, 1.0); // Metallic\n"
+ " if (! uMaterial.Metal) {\n"
+ " diffuseBrdf = color;\n"
+ " }\n"
+ " vec3 l = vec3(0.0);\n"
+ " vec3 lightI = uLightColor[lightIdx];\n"
+ " l = uLightPos[lightIdx] - pos;\n"
+ " float dist = length(l);\n"
+ " l = normalize(l);\n"
+ " lightI /= (dist * dist);\n"
+ " vec3 v = normalize(-pos);\n"
+ " vec3 h = normalize(v + l);\n"
+ " float nDotH = dot(n, h);\n"
+ " float lDotH = dot(l, h);\n"
+ " float nDotL = max(dot(n, l), 0.0);\n"
+ " float nDotV = dot(n, v);\n"
+ " vec4 specBrdf = 0.25 * ggxDistribution(nDotH) *\n"
+ " schlickFresnel(lDotH) * geomSmith(nDotL) * geomSmith(nDotV);\n"
+ " return (diffuseBrdf + PI * specBrdf) * vec4(lightI, 1.0) * nDotL;\n"
+ "}\n"
+ "void main() {\n"
+ " vec4 texColor = texture(uTex2D, ioTexCoord);\n"
+ " if (uEnableTex2D) {\n"
+ " oColor = texColor * uMaterial.Color;\n"
+ " }\n"
+ " else\n"
+ " oColor = uMaterial.Color;\n"
+ " vec4 sum = vec4(0);\n"
+ " vec3 n = normalize(ioNormal);\n"
+ " for (int i = 0; i < uLightCount; i++) {\n"
+ " sum += microfacetModel(i, ioPos, n, oColor);\n"
+ " }\n"
+ " sum = pow(sum, vec4(1.0 / 2.2));\n"
+ " oColor += sum;\n"
+ "}\n";
+
+void gl_camera_bind_texture (s_gl_camera *camera, GLuint texture)
+{
+ assert(camera);
+ assert(glGetError() == GL_NO_ERROR);
+ if (! texture) {
+ glActiveTexture(GL_TEXTURE0);
+ assert(glGetError() == GL_NO_ERROR);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniform1i(camera->gl_enable_tex2d_loc, 0);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniform1i(camera->gl_tex2d_loc, 0);
+ assert(glGetError() == GL_NO_ERROR);
+ return;
+ }
+ glActiveTexture(GL_TEXTURE0);
+ assert(glGetError() == GL_NO_ERROR);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniform1i(camera->gl_enable_tex2d_loc, 1);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniform1i(camera->gl_tex2d_loc, 0);
+ assert(glGetError() == GL_NO_ERROR);
+}
+
+void gl_camera_clean (s_gl_camera *camera)
+{
+ assert(camera);
+ glDeleteProgram(camera->gl_shader_program);
+}
+
+void gl_camera_material (s_gl_camera *camera, const s_gl_material *material)
+{
+ assert(camera);
+ assert(material);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniform1f(camera->gl_material_rough_loc, material->roughness);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniform1i(camera->gl_material_metal_loc, material->metal);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniform4fv(camera->gl_material_color_loc, 1, &material->color.r);
+ assert(glGetError() == GL_NO_ERROR);
+}
+
+void gl_camera_delete (s_gl_camera *camera)
+{
+ gl_camera_clean(camera);
+ free(camera);
+}
+
+s_gl_camera * gl_camera_init (s_gl_camera *camera, uw w, uw h)
+{
+ GLuint fragment_shader;
+ GLint success;
+ GLuint vertex_shader;
+ assert(camera);
+ gl_camera_set_aspect_ratio(camera, w, h);
+ camera->clip_z_far = 10.0f;
+ camera->clip_z_near = 0.1f;
+ camera->fov_y = 90.0f;
+ camera->position.x = 0.0f;
+ camera->position.y = 0.0f;
+ camera->position.z = -10.0f;
+ camera->rotation.x = M_PI / 2.0;
+ camera->rotation.y = 0.0f;
+ camera->rotation.z = 0.0f;
+ camera->light_count = 1;
+ camera->light_pos[0] = (s_vec3) {-100, 0, 0};
+ camera->light_color[0] = (s_rgb) {1, 1, 1};
+ vertex_shader = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(vertex_shader, 1, &g_gl_camera_vertex_shader_src,
+ NULL);
+ glCompileShader(vertex_shader);
+ glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
+ if (! success) {
+ char info_log[512];
+ glGetShaderInfoLog(vertex_shader, sizeof(info_log), NULL, info_log);
+ err_write_1("gl_camera_init: shader compilation failed: ");
+ err_puts(info_log);
+ }
+ fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(fragment_shader, 1, &g_gl_camera_fragment_shader_src,
+ NULL);
+ glCompileShader(fragment_shader);
+ glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
+ if (! success) {
+ char info_log[512];
+ glGetShaderInfoLog(fragment_shader, sizeof(info_log), NULL, info_log);
+ err_write_1("gl_camera_init: shader compilation failed: ");
+ err_puts(info_log);
+ }
+ camera->gl_shader_program = glCreateProgram();
+ glAttachShader(camera->gl_shader_program, vertex_shader);
+ glAttachShader(camera->gl_shader_program, fragment_shader);
+ glLinkProgram(camera->gl_shader_program);
+ glDeleteShader(vertex_shader);
+ glDeleteShader(fragment_shader);
+ camera->gl_projection_matrix_loc =
+ glGetUniformLocation(camera->gl_shader_program,
+ "uProjectionMatrix");
+ camera->gl_view_matrix_loc =
+ glGetUniformLocation(camera->gl_shader_program,
+ "uViewMatrix");
+ camera->gl_model_matrix_loc =
+ glGetUniformLocation(camera->gl_shader_program,
+ "uModelMatrix");
+ camera->gl_enable_tex2d_loc =
+ glGetUniformLocation(camera->gl_shader_program,
+ "uEnableTex2D");
+ camera->gl_tex2d_loc =
+ glGetUniformLocation(camera->gl_shader_program,
+ "uTex2D");
+ camera->gl_light_pos_loc =
+ glGetUniformLocation(camera->gl_shader_program,
+ "uLightPos");
+ camera->gl_light_color_loc =
+ glGetUniformLocation(camera->gl_shader_program,
+ "uLightColor");
+ camera->gl_material_rough_loc =
+ glGetUniformLocation(camera->gl_shader_program,
+ "uMaterial.Rough");
+ camera->gl_material_metal_loc =
+ glGetUniformLocation(camera->gl_shader_program,
+ "uMaterial.Metal");
+ camera->gl_material_color_loc =
+ glGetUniformLocation(camera->gl_shader_program,
+ "uMaterial.Color");
+ return camera;
+}
+
+s_gl_camera * gl_camera_new (uw w, uw h)
+{
+ s_gl_camera *camera;
+ camera = calloc(1, sizeof(s_gl_camera));
+ if (! camera) {
+ err_puts("gl_camera_new: failed to allocate memory");
+ return NULL;
+ }
+ if (! gl_camera_init(camera, w, h)) {
+ free(camera);
+ return NULL;
+ }
+ return camera;
+}
+
+void gl_camera_render (s_gl_camera *camera)
+{
+ s_mat4 matrix;
+ const s_gl_material material = {0.1, false, {1, 1, 1, 1}};
+ assert(camera);
+ assert(glGetError() == GL_NO_ERROR);
+ mat4_init_identity(&camera->projection_matrix);
+ mat4_perspective(&camera->projection_matrix, camera->fov_y,
+ camera->aspect_ratio, camera->clip_z_near,
+ camera->clip_z_far);
+ mat4_init_identity(&camera->view_matrix);
+ mat4_translate(&camera->view_matrix, camera->position.x,
+ camera->position.y, camera->position.z);
+ mat4_rotate_axis(&camera->view_matrix, camera->rotation.x,
+ &(s_vec3) { 1.0f, 0.0f, 0.0f });
+ mat4_rotate_axis(&camera->view_matrix, camera->rotation.y,
+ &(s_vec3) { 0.0f, 1.0f, 0.0f });
+ mat4_rotate_axis(&camera->view_matrix, camera->rotation.z,
+ &(s_vec3) { 0.0f, 0.0f, 1.0f });
+ mat4_init_identity(&camera->model_matrix);
+ mat4_init_copy(&matrix, &camera->view_matrix);
+ for (int i = 0; i < camera->light_count; i++)
+ mat4_mult_vec3(&matrix, camera->light_pos + i,
+ camera->light_pos_cam + i);
+ glUseProgram(camera->gl_shader_program);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniformMatrix4fv(camera->gl_projection_matrix_loc, 1, GL_FALSE,
+ &camera->projection_matrix.xx);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniformMatrix4fv(camera->gl_view_matrix_loc, 1, GL_FALSE,
+ &camera->view_matrix.xx);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniformMatrix4fv(camera->gl_model_matrix_loc, 1, GL_FALSE,
+ &camera->model_matrix.xx);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniform1i(camera->gl_enable_tex2d_loc, 0);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniform1i(camera->gl_tex2d_loc, 0);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniform3fv(camera->gl_light_pos_loc, camera->light_count,
+ &camera->light_pos_cam[0].x);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniform3fv(camera->gl_light_color_loc, camera->light_count,
+ &camera->light_color[0].r);
+ assert(glGetError() == GL_NO_ERROR);
+ gl_camera_material(camera, &material);
+ assert(glGetError() == GL_NO_ERROR);
+ glDisable(GL_CULL_FACE);
+ assert(glGetError() == GL_NO_ERROR);
+ glDepthRange(camera->clip_z_near, camera->clip_z_far);
+ assert(glGetError() == GL_NO_ERROR);
+}
+
+void gl_camera_render_end (s_gl_camera *camera)
+{
+ assert(camera);
+ (void) camera;
+ glUseProgram(0);
+}
+
+s_gl_camera * gl_camera_set_aspect_ratio (s_gl_camera *camera, uw w,
+ uw h)
+{
+ assert(camera);
+ camera->aspect_ratio = (f64) (w ? w : 1) / (h ? h : 1);
+ return camera;
+}
diff --git a/window/sdl2/gl_camera.h b/window/sdl2/gl_camera.h
new file mode 100644
index 0000000..20fbe53
--- /dev/null
+++ b/window/sdl2/gl_camera.h
@@ -0,0 +1,36 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 GL_CAMERA_H
+#define GL_CAMERA_H
+
+#include "types.h"
+
+/* Stack-allocation compatible functions, call gl_camera_clean
+ after use. */
+void gl_camera_clean (s_gl_camera *camera);
+s_gl_camera * gl_camera_init (s_gl_camera *camera, uw w, uw h);
+
+/* Heap-allocation functions, call gl_camera_delete after use. */
+void gl_camera_delete (s_gl_camera *camera);
+s_gl_camera * gl_camera_new (uw w, uw h);
+
+/* Operators. */
+void gl_camera_bind_texture (s_gl_camera *camera,
+ GLuint texture);
+void gl_camera_material (s_gl_camera *camera,
+ const s_gl_material *material);
+void gl_camera_render (s_gl_camera *camera);
+s_gl_camera * gl_camera_set_aspect_ratio (s_gl_camera *camera, uw w,
+ uw h);
+
+#endif /* GL_CAMERA_H */
diff --git a/window/sdl2/gl_cylinder.c b/window/sdl2/gl_cylinder.c
new file mode 100644
index 0000000..62e2f92
--- /dev/null
+++ b/window/sdl2/gl_cylinder.c
@@ -0,0 +1,66 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "gl_object.h"
+#include "gl_cylinder.h"
+
+void gl_cylinder_clean (s_gl_cylinder *cylinder)
+{
+ assert(cylinder);
+ gl_object_clean(&cylinder->object);
+}
+
+s_gl_cylinder * gl_cylinder_init (s_gl_cylinder *cylinder,
+ uw segments_u, uw segments_v)
+{
+ f64 angle;
+ uw i;
+ uw j;
+ s_vec3 *p;
+ f64 z;
+ assert(cylinder);
+ assert(segments_u);
+ assert(segments_v);
+ cylinder->segments_u = segments_u;
+ cylinder->segments_v = segments_v;
+ if (! gl_object_init(&cylinder->object) ||
+ ! gl_object_allocate(&cylinder->object,
+ segments_u * segments_v + 2,
+ 6 * (segments_u + 1) * (segments_v + 2)))
+ return NULL;
+ p = cylinder->object.vertex.data;
+ i = 0;
+ while (i < segments_v) {
+ z = (f64) i / segments_v;
+ j = 0;
+ while (j < segments_u) {
+ angle = (f64) j / segments_u * M_PI * 2.0;
+ p->x = cos(angle);
+ p->y = sin(angle);
+ p->z = z;
+ p++;
+ j++;
+ }
+ i++;
+ }
+ return cylinder;
+}
+
+void gl_cylinder_render (const s_gl_cylinder *cylinder)
+{
+ assert(cylinder);
+ (void) cylinder;
+ glBegin(GL_POINTS);
+ glEnd();
+}
diff --git a/window/sdl2/gl_cylinder.h b/window/sdl2/gl_cylinder.h
new file mode 100644
index 0000000..b1e6edd
--- /dev/null
+++ b/window/sdl2/gl_cylinder.h
@@ -0,0 +1,22 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 GL_CYLINDER_H
+#define GL_CYLINDER_H
+
+#include "types.h"
+
+s_gl_cylinder * gl_cylinder_init (s_gl_cylinder *cylinder,
+ uw segments_u, uw segments_v);
+void gl_cylinder_render (const s_gl_cylinder *cylinder);
+
+#endif /* GL_CYLINDER_H */
diff --git a/window/sdl2/gl_deprecated.c b/window/sdl2/gl_deprecated.c
new file mode 100644
index 0000000..97cd0e7
--- /dev/null
+++ b/window/sdl2/gl_deprecated.c
@@ -0,0 +1,19 @@
+/* kc3
+ * Copyright 2022,2023,2024 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.
+ */
+#define GL_SILENCE_DEPRECATION 1
+#include "gl_deprecated.h"
+
+const char * gl_error_string (GLenum error)
+{
+ return (const char *) gluErrorString(error);
+}
diff --git a/window/sdl2/gl_deprecated.h b/window/sdl2/gl_deprecated.h
new file mode 100644
index 0000000..f7fadbf
--- /dev/null
+++ b/window/sdl2/gl_deprecated.h
@@ -0,0 +1,20 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 C3_GL_DEPRECATED_H
+#define C3_GL_DEPRECATED_H
+
+#include "types.h"
+
+const char * gl_error_string (GLenum error);
+
+#endif /* C3_GL_DEPRECATED_H */
diff --git a/window/sdl2/gl_font.c b/window/sdl2/gl_font.c
new file mode 100644
index 0000000..7a7065e
--- /dev/null
+++ b/window/sdl2/gl_font.c
@@ -0,0 +1,57 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "gl_font.h"
+
+FT_Library g_ft = {0};
+
+void gl_font_clean (s_gl_font *font)
+{
+ assert(font);
+ FT_Done_Face(font->ft_face);
+ str_clean(&font->path);
+ str_clean(&font->real_path);
+}
+
+s_gl_font * gl_font_init (s_gl_font *font, const char *path,
+ f32 point_per_pixel)
+{
+ s_gl_font tmp = {0};
+ assert(font);
+ assert(path);
+ str_init_copy_1(&tmp.path, path);
+ if (! file_search(&tmp.path, sym_1("r"), &tmp.real_path)) {
+ err_write_1("gl_font_init: file not found: ");
+ err_puts(path);
+ str_clean(&tmp.path);
+ return NULL;
+ }
+ assert(glGetError() == GL_NO_ERROR);
+ if (FT_New_Face(g_ft, tmp.real_path.ptr.pchar, 0, &tmp.ft_face)) {
+ err_write_1("gl_font_init: error loading font: ");
+ err_puts(tmp.real_path.ptr.pchar);
+ str_clean(&tmp.path);
+ str_clean(&tmp.real_path);
+ return NULL;
+ }
+ tmp.point_per_pixel = point_per_pixel;
+ *font = tmp;
+ return font;
+}
+
+void gl_font_set_size (s_gl_font *font, f32 point_size)
+{
+ f32 size;
+ size = point_size / font->point_per_pixel;
+ FT_Set_Pixel_Sizes(font->ft_face, 0, size);
+}
diff --git a/window/sdl2/gl_font.h b/window/sdl2/gl_font.h
new file mode 100644
index 0000000..738c0d5
--- /dev/null
+++ b/window/sdl2/gl_font.h
@@ -0,0 +1,29 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 GL_FONT_H
+#define GL_FONT_H
+
+#include "types.h"
+
+extern FT_Library g_ft;
+
+/* Stack-allocation compatible functions, call gl_font_clean
+ after use. */
+void gl_font_clean (s_gl_font *font);
+s_gl_font * gl_font_init (s_gl_font *font, const char *path,
+ f32 point_per_pixel);
+
+/* Operators. */
+void gl_font_set_size (s_gl_font *font, f32 point_size);
+
+#endif /* GL_FONT_H */
diff --git a/window/sdl2/gl_lines.c b/window/sdl2/gl_lines.c
new file mode 100644
index 0000000..7ba19ef
--- /dev/null
+++ b/window/sdl2/gl_lines.c
@@ -0,0 +1,83 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "gl_lines.h"
+#include "gl_vertex.h"
+
+s_gl_lines * gl_lines_allocate (s_gl_lines *lines, uw lines_count)
+{
+ uw vertex_count;
+ assert(lines);
+ assert(lines_count);
+ vertex_count = lines_count * 2;
+ if (! array_init(&lines->vertex, sym_1("GL.Vertex[]"), 1,
+ &vertex_count) ||
+ ! array_allocate(&lines->vertex))
+ return NULL;
+ return lines;
+}
+
+void gl_lines_clean (s_gl_lines *lines)
+{
+ assert(lines);
+ array_clean(&lines->vertex);
+ glDeleteVertexArrays(1, &lines->gl_vao);
+ glDeleteBuffers(1, &lines->gl_vbo);
+}
+
+s_gl_lines * gl_lines_init (s_gl_lines *lines)
+{
+ s_gl_lines tmp = {0};
+ assert(glGetError() == GL_NO_ERROR);
+ glGenVertexArrays(1, &tmp.gl_vao);
+ glGenBuffers(1, &tmp.gl_vbo);
+ assert(glGetError() == GL_NO_ERROR);
+ *lines = tmp;
+ return lines;
+}
+
+void gl_lines_render (const s_gl_lines *lines, uw lines_count)
+{
+ assert(lines);
+ if (lines_count > lines->vertex.count / 2)
+ lines_count = lines->vertex.count / 2;
+ assert(glGetError() == GL_NO_ERROR);
+ glBindVertexArray(lines->gl_vao);
+ assert(glGetError() == GL_NO_ERROR);
+ glBindVertexArray(lines->gl_vao);
+ assert(glGetError() == GL_NO_ERROR);
+ glDrawArrays(GL_LINES, 0, lines_count * 2);
+ assert(glGetError() == GL_NO_ERROR);
+}
+
+bool gl_lines_update (s_gl_lines *lines, uw lines_count)
+{
+ //GLenum gl_error;
+ assert(lines);
+ assert(lines->gl_vao);
+ assert(lines->gl_vbo);
+ assert(lines->vertex.data);
+ assert(glGetError() == GL_NO_ERROR);
+ if (lines_count > lines->vertex.count / 2)
+ lines_count = lines->vertex.count / 2;
+ glBindVertexArray(lines->gl_vao);
+ assert(glGetError() == GL_NO_ERROR);
+ glBindBuffer(GL_ARRAY_BUFFER, lines->gl_vbo);
+ assert(glGetError() == GL_NO_ERROR);
+ glBufferData(GL_ARRAY_BUFFER, lines_count * 2 * sizeof(s_gl_vertex),
+ lines->vertex.data, GL_DYNAMIC_DRAW);
+ assert(glGetError() == GL_NO_ERROR);
+ gl_vertex_attrib();
+ assert(glGetError() == GL_NO_ERROR);
+ return true;
+}
diff --git a/window/sdl2/gl_lines.h b/window/sdl2/gl_lines.h
new file mode 100644
index 0000000..d6f2a97
--- /dev/null
+++ b/window/sdl2/gl_lines.h
@@ -0,0 +1,36 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 GL_LINES_H
+#define GL_LINES_H
+
+#include "types.h"
+
+/* Stack-allocation compatible functions, call gl_lines_clean
+ after use. */
+void gl_lines_clean (s_gl_lines *lines);
+s_gl_lines * gl_lines_init (s_gl_lines *lines);
+
+/* Heap-allocation functions, call gl_lines_delete after use. */
+void gl_lines_delete (s_gl_lines *lines);
+s_gl_lines * gl_lines_new (void);
+
+/* Operators. */
+s_gl_lines * gl_lines_allocate (s_gl_lines *lines, uw lines_count);
+bool gl_lines_update (s_gl_lines *lines, uw lines_count);
+
+/* Observers. */
+void gl_lines_render (const s_gl_lines *lines, uw lines_count);
+void gl_lines_render_wireframe (const s_gl_lines *lines,
+ uw lines_count);
+
+#endif /* GL_LINES_H */
diff --git a/window/sdl2/gl_object.c b/window/sdl2/gl_object.c
new file mode 100644
index 0000000..b99adb5
--- /dev/null
+++ b/window/sdl2/gl_object.c
@@ -0,0 +1,142 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "gl_deprecated.h"
+#include "gl_object.h"
+#include "gl_vertex.h"
+
+s_gl_object * gl_object_allocate (s_gl_object *object, uw vertex_count,
+ uw triangle_count)
+{
+ assert(object);
+ assert(vertex_count);
+ assert(triangle_count);
+ if (! array_init(&object->vertex, sym_1("GL.Vertex[]"), 1,
+ &vertex_count) ||
+ ! array_allocate(&object->vertex) ||
+ ! array_init(&object->triangle, sym_1("GL.Triangle[]"), 1,
+ &triangle_count) ||
+ ! array_allocate(&object->triangle))
+ return NULL;
+ return object;
+}
+
+void gl_object_clean (s_gl_object *object)
+{
+ assert(object);
+ assert(glGetError() == GL_NO_ERROR);
+ if (object->gl_vao)
+ glDeleteVertexArrays(1, &object->gl_vao);
+ assert(glGetError() == GL_NO_ERROR);
+ if (object->gl_vbo)
+ glDeleteBuffers(1, &object->gl_vbo);
+ assert(glGetError() == GL_NO_ERROR);
+ if (object->gl_ebo)
+ glDeleteBuffers(1, &object->gl_ebo);
+ assert(glGetError() == GL_NO_ERROR);
+ array_clean(&object->vertex);
+ array_clean(&object->triangle);
+}
+
+s_gl_object * gl_object_init (s_gl_object *object)
+{
+ s_gl_object tmp = {0};
+ assert(glGetError() == GL_NO_ERROR);
+ glGenVertexArrays(1, &tmp.gl_vao);
+ assert(glGetError() == GL_NO_ERROR);
+ glGenBuffers(1, &tmp.gl_vbo);
+ assert(glGetError() == GL_NO_ERROR);
+ glGenBuffers(1, &tmp.gl_ebo);
+ assert(glGetError() == GL_NO_ERROR);
+ *object = tmp;
+ return object;
+}
+
+void gl_object_render (const s_gl_object *object)
+{
+ GLenum error;
+ assert(object);
+ assert(glGetError() == GL_NO_ERROR);
+ glBindVertexArray(object->gl_vao);
+ assert(glGetError() == GL_NO_ERROR);
+ glBindBuffer(GL_ARRAY_BUFFER, object->gl_vbo);
+ assert(glGetError() == GL_NO_ERROR);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object->gl_ebo);
+ assert(glGetError() == GL_NO_ERROR);
+ glDrawElements(GL_TRIANGLES, object->triangle.count * 3, GL_UNSIGNED_INT,
+ NULL);
+ if ((error = glGetError()) != GL_NO_ERROR) {
+ err_write_1("gl_object_render: glDrawElements: ");
+ err_puts(gl_error_string(error));
+ assert(! "gl_object_render: glDrawElements");
+ }
+ assert(glGetError() == GL_NO_ERROR);
+}
+
+void gl_object_render_wireframe (const s_gl_object *object)
+{
+ assert(object);
+ assert(glGetError() == GL_NO_ERROR);
+ glBindVertexArray(object->gl_vao);
+ assert(glGetError() == GL_NO_ERROR);
+ glBindBuffer(GL_ARRAY_BUFFER, object->gl_vbo);
+ assert(glGetError() == GL_NO_ERROR);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object->gl_ebo);
+ assert(glGetError() == GL_NO_ERROR);
+ glDrawElements(GL_LINE_LOOP, object->triangle.count * 3,
+ GL_UNSIGNED_INT,
+ NULL);
+ assert(glGetError() == GL_NO_ERROR);
+}
+
+void gl_object_transform (s_gl_object *object, const s_mat4 *matrix)
+{
+ uw i;
+ s_gl_vertex *vertex;
+ assert(object);
+ assert(matrix);
+ vertex = object->vertex.data;
+ i = 0;
+ while (i < object->vertex.count) {
+ gl_vertex_transform(vertex, matrix);
+ vertex++;
+ i++;
+ }
+}
+
+bool gl_object_update (s_gl_object *object)
+{
+ //GLenum gl_error;
+ assert(object);
+ assert(object->gl_vao);
+ assert(object->gl_vbo);
+ assert(object->gl_ebo);
+ assert(object->vertex.data);
+ assert(object->triangle.data);
+ assert(glGetError() == GL_NO_ERROR);
+ glBindVertexArray(object->gl_vao);
+ assert(glGetError() == GL_NO_ERROR);
+ glBindBuffer(GL_ARRAY_BUFFER, object->gl_vbo);
+ assert(glGetError() == GL_NO_ERROR);
+ glBufferData(GL_ARRAY_BUFFER, object->vertex.count * sizeof(s_gl_vertex),
+ object->vertex.data, GL_DYNAMIC_DRAW);
+ assert(glGetError() == GL_NO_ERROR);
+ gl_vertex_attrib();
+ assert(glGetError() == GL_NO_ERROR);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object->gl_ebo);
+ assert(glGetError() == GL_NO_ERROR);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, object->triangle.count * sizeof(s_gl_triangle),
+ object->triangle.data, GL_DYNAMIC_DRAW);
+ assert(glGetError() == GL_NO_ERROR);
+ return true;
+}
diff --git a/window/sdl2/gl_object.h b/window/sdl2/gl_object.h
new file mode 100644
index 0000000..cea10d3
--- /dev/null
+++ b/window/sdl2/gl_object.h
@@ -0,0 +1,38 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 GL_OBJECT_H
+#define GL_OBJECT_H
+
+#include "types.h"
+
+/* Stack-allocation compatible functions, call gl_object_clean
+ after use. */
+void gl_object_clean (s_gl_object *object);
+s_gl_object * gl_object_init (s_gl_object *object);
+
+/* Heap-allocation functions, call gl_object_delete after use. */
+void gl_object_delete (s_gl_object *object);
+s_gl_object * gl_object_new (void);
+
+/* Operators. */
+s_gl_object * gl_object_allocate (s_gl_object *object, uw vertex_count,
+ uw index_count);
+void gl_object_transform (s_gl_object *object,
+ const s_mat4 *matrix);
+bool gl_object_update (s_gl_object *object);
+
+/* Observers. */
+void gl_object_render (const s_gl_object *object);
+void gl_object_render_wireframe (const s_gl_object *object);
+
+#endif /* GL_OBJECT_H */
diff --git a/window/sdl2/gl_ortho.c b/window/sdl2/gl_ortho.c
new file mode 100644
index 0000000..54d7f10
--- /dev/null
+++ b/window/sdl2/gl_ortho.c
@@ -0,0 +1,352 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "gl_deprecated.h"
+#include "mat4.h"
+#include "gl_ortho.h"
+#include "gl_square.h"
+
+static const char * g_gl_ortho_vertex_shader_src =
+ "#version 330 core\n"
+ "layout (location = 0) in vec3 iPos;\n"
+ "layout (location = 1) in vec3 iNormal;\n"
+ "layout (location = 2) in vec2 iTexCoord;\n"
+ "out vec3 ioFragNormal;\n"
+ "out vec2 ioTexCoord;\n"
+ "uniform mat4 uProjectionMatrix;\n"
+ "uniform mat4 uViewMatrix;\n"
+ "uniform mat4 uModelMatrix;\n"
+ "void main() {\n"
+ " gl_Position = vec4(uProjectionMatrix * uViewMatrix * \n"
+ " uModelMatrix * vec4(iPos, 1.0));\n"
+ " ioTexCoord = iTexCoord;\n"
+ " ioFragNormal = vec3(mat3(transpose(inverse(uModelMatrix))) *\n"
+ " iNormal);\n"
+ "}\n";
+
+static const char * g_gl_ortho_fragment_shader_src =
+ "#version 330 core\n"
+ "in vec3 ioFragNormal;\n"
+ "in vec2 ioTexCoord;\n"
+ "out vec4 oFragColor;\n"
+ "uniform vec4 uColor;\n"
+ "uniform bool uEnableTex2D;\n"
+ "uniform sampler2D uTex2D;\n"
+ "void main() {\n"
+ " vec4 texColor = texture(uTex2D, ioTexCoord);\n"
+ " if (uEnableTex2D) {\n"
+ " oFragColor = vec4(texColor[0] * uColor[0],\n"
+ " texColor[1] * uColor[1],\n"
+ " texColor[2] * uColor[2],\n"
+ " texColor[3] * uColor[3]);\n"
+ " }\n"
+ " else\n"
+ " oFragColor = uColor;\n"
+ "}\n";
+
+void gl_ortho_bind_texture (s_gl_ortho *ortho, GLuint texture)
+{
+ assert(ortho);
+ assert(glGetError() == GL_NO_ERROR);
+ if (! texture) {
+ glActiveTexture(GL_TEXTURE0);
+ assert(glGetError() == GL_NO_ERROR);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniform1i(ortho->gl_enable_tex2d_loc, 0);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniform1i(ortho->gl_tex2d_loc, 0);
+ assert(glGetError() == GL_NO_ERROR);
+ return;
+ }
+ glActiveTexture(GL_TEXTURE0);
+ assert(glGetError() == GL_NO_ERROR);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniform1i(ortho->gl_enable_tex2d_loc, 1);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniform1i(ortho->gl_tex2d_loc, 0);
+ assert(glGetError() == GL_NO_ERROR);
+}
+
+void gl_ortho_clean (s_gl_ortho *ortho)
+{
+ assert(ortho);
+ assert(glGetError() == GL_NO_ERROR);
+ glDeleteProgram(ortho->gl_shader_program);
+ assert(glGetError() == GL_NO_ERROR);
+ gl_square_clean(&ortho->square);
+ assert(glGetError() == GL_NO_ERROR);
+}
+
+void gl_ortho_color (s_gl_ortho *ortho, f32 r, f32 g, f32 b, f32 a)
+{
+ s_rgba color = {r, g, b, a};
+ assert(ortho);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniform4fv(ortho->gl_color_loc, 1, &color.r);
+ assert(glGetError() == GL_NO_ERROR);
+}
+
+void gl_ortho_delete (s_gl_ortho *ortho)
+{
+ gl_ortho_clean(ortho);
+ free(ortho);
+}
+
+s_gl_ortho * gl_ortho_init (s_gl_ortho *ortho)
+{
+ GLuint fragment_shader;
+ GLint success;
+ GLuint vertex_shader;
+ assert(ortho);
+ if (! gl_square_init(&ortho->square, 2, 2))
+ return NULL;
+ mat4_init_identity(&ortho->projection_matrix);
+ mat4_ortho(&ortho->projection_matrix, -1, 1, -1, 1, 0, 1);
+ ortho->position.x = 0.0f;
+ ortho->position.y = 0.0f;
+ ortho->position.z = 0.0f;
+ ortho->rotation.x = 0.0f;
+ ortho->rotation.y = 0.0f;
+ ortho->rotation.z = 0.0f;
+ ortho->scale.x = 1.0f;
+ ortho->scale.y = 1.0f;
+ ortho->scale.z = 1.0f;
+ mat4_init_identity(&ortho->view_matrix);
+ mat4_init_identity(&ortho->model_matrix);
+ vertex_shader = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(vertex_shader, 1, &g_gl_ortho_vertex_shader_src,
+ NULL);
+ glCompileShader(vertex_shader);
+ glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
+ if (! success) {
+ char info_log[512];
+ glGetShaderInfoLog(vertex_shader, sizeof(info_log), NULL, info_log);
+ err_write_1("gl_ortho_init: shader compilation failed: ");
+ err_puts(info_log);
+ }
+ fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(fragment_shader, 1, &g_gl_ortho_fragment_shader_src,
+ NULL);
+ glCompileShader(fragment_shader);
+ glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
+ if (! success) {
+ char info_log[512];
+ glGetShaderInfoLog(fragment_shader, sizeof(info_log), NULL, info_log);
+ err_write_1("gl_ortho_init: shader compilation failed: ");
+ err_puts(info_log);
+ }
+ ortho->gl_shader_program = glCreateProgram();
+ assert(glGetError() == GL_NO_ERROR);
+ glAttachShader(ortho->gl_shader_program, vertex_shader);
+ assert(glGetError() == GL_NO_ERROR);
+ glAttachShader(ortho->gl_shader_program, fragment_shader);
+ assert(glGetError() == GL_NO_ERROR);
+ glLinkProgram(ortho->gl_shader_program);
+ assert(glGetError() == GL_NO_ERROR);
+ glDeleteShader(vertex_shader);
+ assert(glGetError() == GL_NO_ERROR);
+ glDeleteShader(fragment_shader);
+ assert(glGetError() == GL_NO_ERROR);
+ ortho->gl_projection_matrix_loc =
+ glGetUniformLocation(ortho->gl_shader_program, "uProjectionMatrix");
+ assert(glGetError() == GL_NO_ERROR);
+ ortho->gl_view_matrix_loc =
+ glGetUniformLocation(ortho->gl_shader_program, "uViewMatrix");
+ assert(glGetError() == GL_NO_ERROR);
+ ortho->gl_model_matrix_loc =
+ glGetUniformLocation(ortho->gl_shader_program, "uModelMatrix");
+ assert(glGetError() == GL_NO_ERROR);
+ ortho->gl_enable_tex2d_loc =
+ glGetUniformLocation(ortho->gl_shader_program, "uEnableTex2D");
+ assert(glGetError() == GL_NO_ERROR);
+ ortho->gl_tex2d_loc =
+ glGetUniformLocation(ortho->gl_shader_program, "uTex2D");
+ assert(glGetError() == GL_NO_ERROR);
+ ortho->gl_color_loc =
+ glGetUniformLocation(ortho->gl_shader_program, "uColor");
+ assert(glGetError() == GL_NO_ERROR);
+ return ortho;
+}
+
+s_gl_ortho * gl_ortho_new (void)
+{
+ s_gl_ortho *ortho;
+ ortho = calloc(1, sizeof(s_gl_ortho));
+ if (! ortho) {
+ err_puts("gl_ortho_new: failed to allocate memory");
+ return NULL;
+ }
+ if (! gl_ortho_init(ortho)) {
+ free(ortho);
+ return NULL;
+ }
+ return ortho;
+}
+
+void gl_ortho_rect (s_gl_ortho *ortho, f32 x, f32 y, f32 w, f32 h)
+{
+ s_mat4 matrix;
+ assert(ortho);
+ assert(glGetError() == GL_NO_ERROR);
+ matrix = ortho->model_matrix;
+ mat4_translate(&ortho->model_matrix, x, y, 0.0f);
+ mat4_scale(&ortho->model_matrix, w, h, 1.0f);
+ gl_ortho_update_model_matrix(ortho);
+ assert(glGetError() == GL_NO_ERROR);
+ gl_square_render(&ortho->square);
+ assert(glGetError() == GL_NO_ERROR);
+ ortho->model_matrix = matrix;
+ gl_ortho_update_model_matrix(ortho);
+}
+
+void gl_ortho_render (s_gl_ortho *ortho)
+{
+ GLenum error;
+ assert(ortho);
+ assert(glGetError() == GL_NO_ERROR);
+ glUseProgram(ortho->gl_shader_program);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniformMatrix4fv(ortho->gl_projection_matrix_loc, 1, GL_FALSE,
+ &ortho->projection_matrix.xx);
+ if ((error = glGetError()) != GL_NO_ERROR) {
+ err_write_1("gl_ortho_render: glUniformMatrix4fv: ");
+ err_puts(gl_error_string(error));
+ assert(! "gl_ortho_render: glUniformMatrix4fv");
+ }
+ assert(glGetError() == GL_NO_ERROR);
+ glUniformMatrix4fv(ortho->gl_view_matrix_loc, 1, GL_FALSE,
+ &ortho->view_matrix.xx);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniformMatrix4fv(ortho->gl_model_matrix_loc, 1, GL_FALSE,
+ &ortho->model_matrix.xx);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniform1i(ortho->gl_enable_tex2d_loc, 0);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniform1i(ortho->gl_tex2d_loc, 0);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniform4f(ortho->gl_color_loc, 1.0f, 1.0f, 1.0f, 1.0f);
+ assert(glGetError() == GL_NO_ERROR);
+ glDepthRange(ortho->clip_z_near, ortho->clip_z_far);
+ assert(glGetError() == GL_NO_ERROR);
+}
+
+void gl_ortho_render_end (s_gl_ortho *ortho)
+{
+ assert(ortho);
+ (void) ortho;
+ assert(glGetError() == GL_NO_ERROR);
+ glUseProgram(0);
+ assert(glGetError() == GL_NO_ERROR);
+}
+
+void gl_ortho_resize (s_gl_ortho *ortho, f32 x1, f32 x2, f32 y1, f32 y2,
+ f32 clip_z_near, f32 clip_z_far)
+{
+ assert(ortho);
+ mat4_init_identity(&ortho->projection_matrix);
+ mat4_ortho(&ortho->projection_matrix, x1, x2, y1, y2,
+ clip_z_near, clip_z_far);
+}
+
+void gl_ortho_text_render (s_gl_ortho *ortho, const s_gl_text *text)
+{
+ assert(ortho);
+ assert(text);
+ gl_ortho_bind_texture(ortho, text->texture);
+ gl_ortho_rect(ortho, 0, 0, text->pt_w, text->pt_h);
+ gl_ortho_bind_texture(ortho, 0);
+}
+
+void gl_ortho_text_render_outline (s_gl_ortho *ortho, s_gl_text *text,
+ f64 x, f64 y)
+{
+ s_mat4 matrix;
+ assert(glGetError() == GL_NO_ERROR);
+ glEnable(GL_BLEND);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
+ GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ assert(glGetError() == GL_NO_ERROR);
+ gl_ortho_bind_texture(ortho, text->texture);
+ assert(glGetError() == GL_NO_ERROR);
+ gl_ortho_color(ortho, 1.0f, 1.0f, 1.0f, 1.0f);
+ assert(glGetError() == GL_NO_ERROR);
+ matrix = ortho->model_matrix;
+ gl_ortho_rect(ortho, x - 1.0, y - 1.0, text->pt_w, text->pt_h);
+ gl_ortho_rect(ortho, x, y - 1.0, text->pt_w, text->pt_h);
+ gl_ortho_rect(ortho, x + 1.0, y - 1.0, text->pt_w, text->pt_h);
+ gl_ortho_rect(ortho, x - 1.0, y, text->pt_w, text->pt_h);
+ //gl_ortho_rect(ortho, x, y, text->pt_w, text->pt_h);
+ gl_ortho_rect(ortho, x + 1.0, y, text->pt_w, text->pt_h);
+ gl_ortho_rect(ortho, x - 1.0, y + 1.0, text->pt_w, text->pt_h);
+ gl_ortho_rect(ortho, x, y + 1.0, text->pt_w, text->pt_h);
+ gl_ortho_rect(ortho, x + 1.0, y + 1.0, text->pt_w, text->pt_h);
+ gl_ortho_color(ortho, 0.0f, 0.0f, 0.0f, 1.0f);
+ assert(glGetError() == GL_NO_ERROR);
+ gl_ortho_rect(ortho, x, y, text->pt_w, text->pt_h);
+ assert(glGetError() == GL_NO_ERROR);
+ ortho->model_matrix = matrix;
+ gl_ortho_update_model_matrix(ortho);
+ assert(glGetError() == GL_NO_ERROR);
+}
+
+void gl_ortho_update_model_matrix (s_gl_ortho *ortho)
+{
+ assert(ortho);
+ assert(glGetError() == GL_NO_ERROR);
+ glUniformMatrix4fv(ortho->gl_model_matrix_loc, 1, GL_FALSE,
+ &ortho->model_matrix.xx);
+ assert(glGetError() == GL_NO_ERROR);
+ /*
+ err_puts("gl_ortho_update_model_matrix projection matrix");
+ mat4_buf_inspect(&g_c3_env.err, &ortho->projection_matrix);
+ err_puts("view matrix");
+ mat4_buf_inspect(&g_c3_env.err, &ortho->view_matrix);
+ err_puts("model matrix");
+ mat4_buf_inspect(&g_c3_env.err, &ortho->model_matrix);
+ buf_flush(&g_c3_env.err);
+ */
+}
+
+void gl_ortho_update_view_matrix (s_gl_ortho *ortho)
+{
+ assert(ortho);
+ assert(glGetError() == GL_NO_ERROR);
+ mat4_init_identity(&ortho->view_matrix);
+ mat4_translate(&ortho->view_matrix, ortho->position.x,
+ ortho->position.y, ortho->position.z);
+ mat4_rotate_axis(&ortho->view_matrix, ortho->rotation.x,
+ &(s_vec3) { 1.0f, 0.0f, 0.0f });
+ mat4_rotate_axis(&ortho->view_matrix, ortho->rotation.y,
+ &(s_vec3) { 0.0f, 1.0f, 0.0f });
+ mat4_rotate_axis(&ortho->view_matrix, ortho->rotation.z,
+ &(s_vec3) { 0.0f, 0.0f, 1.0f });
+ mat4_scale(&ortho->view_matrix, ortho->scale.x,
+ ortho->scale.y, ortho->scale.z);
+ glUniformMatrix4fv(ortho->gl_view_matrix_loc, 1, GL_FALSE,
+ &ortho->view_matrix.xx);
+ assert(glGetError() == GL_NO_ERROR);
+}
+
+void gl_ortho_vtext_render (s_gl_ortho *ortho, const s_gl_text *text)
+{
+ assert(ortho);
+ assert(text);
+ gl_ortho_bind_texture(ortho, text->texture);
+ gl_ortho_rect(ortho, 0, -text->pt_h, text->pt_w, text->pt_h);
+ gl_ortho_bind_texture(ortho, 0);
+}
diff --git a/window/sdl2/gl_ortho.h b/window/sdl2/gl_ortho.h
new file mode 100644
index 0000000..0254055
--- /dev/null
+++ b/window/sdl2/gl_ortho.h
@@ -0,0 +1,47 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 GL_ORTHO_H
+#define GL_ORTHO_H
+
+#include "types.h"
+
+/* Stack-allocation compatible functions, call gl_ortho_clean
+ after use. */
+void gl_ortho_clean (s_gl_ortho *ortho);
+s_gl_ortho * gl_ortho_init (s_gl_ortho *ortho);
+
+/* Heap-allocation functions, call gl_ortho_delete after use. */
+void gl_ortho_delete (s_gl_ortho *ortho);
+s_gl_ortho * gl_ortho_new (void);
+
+/* Operators. */
+void gl_ortho_bind_texture (s_gl_ortho *ortho, GLuint texture);
+void gl_ortho_color (s_gl_ortho *ortho, f32 r, f32 g, f32 b,
+ f32 a);
+void gl_ortho_rect (s_gl_ortho *ortho, f32 x1, f32 x2, f32 y1,
+ f32 y2);
+void gl_ortho_render (s_gl_ortho *ortho);
+void gl_ortho_render_end (s_gl_ortho *ortho);
+void gl_ortho_resize (s_gl_ortho *ortho, f32 x1, f32 x2, f32 y1,
+ f32 y2, f32 clip_z_near, f32 clip_z_far);
+void gl_ortho_text_render (s_gl_ortho *ortho,
+ const s_gl_text *text);
+void gl_ortho_text_render_outline (s_gl_ortho *ortho,
+ s_gl_text *text,
+ f64 x, f64 y);
+void gl_ortho_update_model_matrix (s_gl_ortho *ortho);
+void gl_ortho_update_view_matrix (s_gl_ortho *ortho);
+void gl_ortho_vtext_render (s_gl_ortho *ortho,
+ const s_gl_text *text);
+
+#endif /* GL_ORTHO_H */
diff --git a/window/sdl2/gl_sphere.c b/window/sdl2/gl_sphere.c
new file mode 100644
index 0000000..a05e044
--- /dev/null
+++ b/window/sdl2/gl_sphere.c
@@ -0,0 +1,169 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "gl_object.h"
+#include "gl_sphere.h"
+
+void gl_sphere_clean (s_gl_sphere *sphere)
+{
+ assert(sphere);
+ gl_object_clean(&sphere->object);
+}
+
+void gl_sphere_delete (s_gl_sphere *sphere)
+{
+ assert(sphere);
+ gl_sphere_clean(sphere);
+ free(sphere);
+}
+
+s_gl_sphere * gl_sphere_init (s_gl_sphere *sphere, uw seg_u, uw seg_v)
+{
+ f64 angle_i;
+ f64 angle_j;
+ uw i;
+ uw j;
+ s_gl_vertex *vertex;
+ f64 r;
+ s_gl_sphere tmp = {0};
+ s_gl_triangle *triangle;
+ f64 z;
+ assert(sphere);
+ if (seg_u < 3)
+ seg_u = 3;
+ if (seg_v < 1)
+ seg_v = 1;
+ tmp.segments_u = seg_u;
+ tmp.segments_v = seg_v;
+ if (! gl_object_init(&tmp.object) ||
+ ! gl_object_allocate(&tmp.object, (seg_u + 1) * (seg_v + 2),
+ 2 * seg_u * (seg_v + 1)))
+ return NULL;
+ vertex = tmp.object.vertex.data;
+ i = 0;
+ while (i <= seg_v + 1) {
+ angle_i = (f64) i * M_PI / (seg_v + 1);
+ r = sin(angle_i);
+ z = cos(angle_i);
+ j = 0;
+ while (j <= seg_u) {
+ angle_j = j * M_PI * 2.0 / seg_u;
+ vertex->pos_x = cos(angle_j) * r;
+ vertex->pos_y = sin(angle_j) * r;
+ vertex->pos_z = z;
+ vertex->normal_x = vertex->pos_x;
+ vertex->normal_y = vertex->pos_y;
+ vertex->normal_z = vertex->pos_z;
+ vertex->tex_coord_x = (f64) (seg_u - j) / seg_u;
+ vertex->tex_coord_y = (f64) i / (seg_v + 1);
+ vertex++;
+ j++;
+ }
+ i++;
+ }
+ triangle = tmp.object.triangle.data;
+ i = 0;
+ while (i < seg_v + 1) {
+ j = 0;
+ while (j < seg_u) {
+ triangle->a = i * (seg_u + 1) + j;
+ triangle->b = (i + 1) * (seg_u + 1) + j;
+ triangle->c = (i + 1) * (seg_u + 1) + j + 1;
+ triangle++;
+ triangle->a = i * (seg_u + 1) + j;
+ triangle->b = (i + 1) * (seg_u + 1) + j + 1;
+ triangle->c = i * (seg_u + 1) + j + 1;
+ triangle++;
+ j++;
+ }
+ i++;
+ }
+ *sphere = tmp;
+ return sphere;
+}
+
+s_gl_sphere * gl_sphere_new (uw segments_u, uw segments_v)
+{
+ s_gl_sphere *sphere;
+ sphere = calloc(1, sizeof(s_gl_sphere));
+ if (! sphere) {
+ err_puts("gl_sphere_new: failed to allocate memory");
+ return NULL;
+ }
+ if (! gl_sphere_init(sphere, segments_u, segments_v)) {
+ free(sphere);
+ return NULL;
+ }
+ return sphere;
+}
+
+void gl_sphere_render (const s_gl_sphere *sphere)
+{
+ assert(sphere);
+ gl_object_render(&sphere->object);
+}
+
+/*
+void gl_sphere_render_wireframe (const s_gl_sphere *sphere)
+{
+ uw i;
+ uw j;
+ s_gl_3d *p[3];
+ uw seg_u;
+ uw seg_v;
+ assert(sphere);
+ seg_u = sphere->segments_u;
+ seg_v = sphere->segments_v;
+ // first row
+ j = 0;
+ while (j < seg_u + 1) {
+ glBegin(GL_LINE_STRIP);
+ p[0] = sphere->vertex + seg_u * seg_v;
+ p[1] = sphere->vertex + j % seg_u;
+ p[2] = sphere->vertex + (j + 1) % seg_u;
+ gl_vertex_3d(p[0]);
+ gl_vertex_3d(p[1]);
+ gl_vertex_3d(p[2]);
+ glEnd();
+ j++;
+ }
+ // whole
+ i = 1;
+ while (i < seg_v) {
+ j = 0;
+ while (j < seg_u + 1) {
+ glBegin(GL_LINE_STRIP);
+ p[0] = sphere->vertex + (i - 1) * seg_u + j % seg_u;
+ p[1] = sphere->vertex + i * seg_u + j % seg_u;
+ p[2] = sphere->vertex + i * seg_u + (j + 1) % seg_u;
+ gl_vertex_3d(p[0]);
+ gl_vertex_3d(p[1]);
+ gl_vertex_3d(p[2]);
+ glEnd();
+ j++;
+ }
+ i++;
+ }
+ glBegin(GL_LINES);
+ j = 0;
+ while (j < seg_u + 1) {
+ p[0] = sphere->vertex + seg_u * seg_v + 1;
+ p[1] = sphere->vertex + (seg_v - 1) * seg_u + j % seg_u;
+ gl_vertex_3d(p[0]);
+ gl_vertex_3d(p[1]);
+ j++;
+ }
+ glEnd();
+}
+*/
diff --git a/window/sdl2/gl_sphere.h b/window/sdl2/gl_sphere.h
new file mode 100644
index 0000000..81e6611
--- /dev/null
+++ b/window/sdl2/gl_sphere.h
@@ -0,0 +1,32 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 GL_SPHERE_H
+#define GL_SPHERE_H
+
+#include "types.h"
+
+/* Stack-allocation compatible functions, call gl_sphere_clean after
+ use. */
+void gl_sphere_clean (s_gl_sphere *sphere);
+s_gl_sphere * gl_sphere_init (s_gl_sphere *sphere, uw segments_u,
+ uw segments_v);
+
+/* Heap-allocation functions, call gl_sphere_delete after use. */
+void gl_sphere_delete (s_gl_sphere *sphere);
+s_gl_sphere * gl_sphere_new (uw segments_u, uw segments_v);
+
+/* Observers. */
+void gl_sphere_render (const s_gl_sphere *sphere);
+void gl_sphere_render_wireframe (const s_gl_sphere *sphere);
+
+#endif /* GL_SPHERE_H */
diff --git a/window/sdl2/gl_sprite.c b/window/sdl2/gl_sprite.c
new file mode 100644
index 0000000..dc618d4
--- /dev/null
+++ b/window/sdl2/gl_sprite.c
@@ -0,0 +1,341 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "gl_deprecated.h"
+#include "gl_object.h"
+#include "gl_sprite.h"
+#include "gl_triangle.h"
+
+void gl_sprite_clean (s_gl_sprite *sprite)
+{
+ assert(sprite);
+ str_clean(&sprite->path);
+ str_clean(&sprite->real_path);
+ glDeleteTextures(sprite->frame_count, sprite->texture);
+ free(sprite->texture);
+}
+
+static bool png_info_to_gl_info (s32 png_color_type,
+ s32 png_bit_depth,
+ GLenum *gl_format,
+ GLint *gl_internal_format,
+ GLenum *gl_type,
+ u8 *components)
+{
+ switch (png_bit_depth) {
+ case 8: *gl_type = GL_UNSIGNED_BYTE; break;
+ case 16: *gl_type = GL_UNSIGNED_SHORT; break;
+ default: *gl_type = 0; return false;
+ }
+ switch (png_color_type) {
+ case PNG_COLOR_TYPE_GRAY:
+ *components = 1;
+ *gl_format = GL_RED;
+ switch (png_bit_depth) {
+ case 8: *gl_internal_format = GL_RED; break;
+ case 16: *gl_internal_format = GL_RED; break;
+ default: *gl_internal_format = 0; return false;
+ }
+ break;
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ *components = 2;
+ *gl_format = GL_RG;
+ switch (png_bit_depth) {
+ case 8: *gl_internal_format = GL_RG; break;
+ case 16: *gl_internal_format = GL_RG; break;
+ default: *gl_internal_format = 0; return false;
+ }
+ break;
+ case PNG_COLOR_TYPE_RGB:
+ *components = 3;
+ *gl_format = GL_RGB;
+ switch (png_bit_depth) {
+ case 8: *gl_internal_format = GL_RGB; break;
+ case 16: *gl_internal_format = GL_RGB; break;
+ default: *gl_internal_format = 0; return false;
+ }
+ break;
+ case PNG_COLOR_TYPE_RGBA:
+ *components = 4;
+ *gl_format = GL_RGBA;
+ switch (png_bit_depth) {
+ case 8: *gl_internal_format = GL_RGBA; break;
+ case 16: *gl_internal_format = GL_RGBA; break;
+ default: *gl_internal_format = 0; return false;
+ }
+ break;
+ default:
+ *components = 0;
+ *gl_format = 0;
+ *gl_internal_format = 0;
+ return false;
+ }
+ return true;
+}
+
+s_gl_sprite * gl_sprite_init (s_gl_sprite *sprite, const char *path,
+ uw dim_x, uw dim_y, uw frame_count,
+ f32 point_per_pixel)
+{
+ u8 *data;
+ FILE *fp;
+ GLenum gl_format;
+ GLint gl_internal_format;
+ GLenum gl_type;
+ uw i;
+ s32 png_bit_depth;
+ s32 png_color_type;
+ u8 png_components;
+ png_bytep png_data;
+ u32 png_h;
+ u8 png_header[8]; // maximum size is 8
+ png_infop png_info;
+ uw png_pixel_size;
+ png_structp png_read;
+ png_bytep *png_row;
+ u32 png_w;
+ u8 *sprite_data;
+ uw sprite_stride;
+ uw x;
+ uw y;
+ uw v;
+ s_gl_sprite tmp = {0};
+ assert(sprite);
+ assert(path);
+ assert(dim_x);
+ assert(dim_y);
+ assert(glGetError() == GL_NO_ERROR);
+ tmp.frame_count = (frame_count > 0) ? frame_count :
+ (dim_x * dim_y);
+ str_init_copy_1(&tmp.path, path);
+ if (! file_search(&tmp.path, sym_1("r"), &tmp.real_path)) {
+ err_write_1("gl_sprite_init: file not found: ");
+ err_puts(path);
+ str_clean(&tmp.path);
+ return NULL;
+ }
+ fp = fopen(tmp.real_path.ptr.pchar, "rb");
+ if (! fp) {
+ err_write_1("gl_sprite_init: fopen: ");
+ err_puts(tmp.real_path.ptr.pchar);
+ str_clean(&tmp.path);
+ str_clean(&tmp.real_path);
+ return NULL;
+ }
+ if (fread(png_header, 1, sizeof(png_header), fp) !=
+ sizeof(png_header)) {
+ err_write_1("gl_sprite_init: fread: ");
+ err_puts(tmp.real_path.ptr.pchar);
+ fclose(fp);
+ str_clean(&tmp.path);
+ str_clean(&tmp.real_path);
+ return NULL;
+ }
+ if (png_sig_cmp(png_header, 0, sizeof(png_header))) {
+ err_write_1("gl_sprite_init: not a png: ");
+ err_puts(tmp.real_path.ptr.pchar);
+ fclose(fp);
+ str_clean(&tmp.path);
+ str_clean(&tmp.real_path);
+ return NULL;
+ }
+ png_read = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL,
+ NULL);
+ if (! png_read) {
+ err_write_1("gl_sprite_init: png_create_read_struct: ");
+ err_puts(tmp.real_path.ptr.pchar);
+ fclose(fp);
+ str_clean(&tmp.path);
+ str_clean(&tmp.real_path);
+ return NULL;
+ }
+ png_info = png_create_info_struct(png_read);
+ if (! png_info) {
+ err_write_1("gl_sprite_init: png_create_info_struct: ");
+ err_puts(tmp.real_path.ptr.pchar);
+ png_destroy_read_struct(&png_read, NULL, NULL);
+ fclose(fp);
+ str_clean(&tmp.path);
+ str_clean(&tmp.real_path);
+ return NULL;
+ }
+ gl_internal_format = 0;
+ gl_format = 0;
+ gl_type = 0;
+ png_components = 0;
+ if (setjmp(png_jmpbuf(png_read))) {
+ png_destroy_read_struct(&png_read, &png_info, NULL);
+ fclose(fp);
+ str_clean(&tmp.path);
+ str_clean(&tmp.real_path);
+ return NULL;
+ }
+ png_set_sig_bytes(png_read, sizeof(png_header));
+ png_init_io(png_read, fp);
+ png_read_info(png_read, png_info);
+ png_get_IHDR(png_read, png_info, &png_w, &png_h,
+ &png_bit_depth, &png_color_type,
+ NULL, NULL, NULL);
+ if (png_color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_palette_to_rgb(png_read);
+ if (! png_info_to_gl_info(png_color_type, png_bit_depth, &gl_format,
+ &gl_internal_format, &gl_type,
+ &png_components)) {
+ if (! gl_format || ! png_components) {
+ err_write_1("gl_sprite_init: unknown PNG color type ");
+ err_inspect_s32(&png_color_type);
+ err_write_1(": ");
+ err_puts(tmp.real_path.ptr.pchar);
+ }
+ if (! gl_internal_format) {
+ err_write_1("gl_sprite_init: unknown OpenGL internal format: ");
+ err_puts(tmp.real_path.ptr.pchar);
+ }
+ if (! gl_type) {
+ err_write_1("gl_sprite_init: unknown OpenGL type: ");
+ err_puts(tmp.real_path.ptr.pchar);
+ }
+ png_destroy_read_struct(&png_read, &png_info, NULL);
+ fclose(fp);
+ str_clean(&tmp.path);
+ str_clean(&tmp.real_path);
+ return NULL;
+ }
+ png_pixel_size = (png_bit_depth / 8) * png_components;
+ if (! png_pixel_size)
+ png_error(png_read, "unknown png pixel size");
+ if (png_h > PNG_SIZE_MAX / (png_w * png_pixel_size))
+ png_error(png_read, "image_data buffer would be too large");
+ png_data = png_malloc(png_read, png_h * png_w * png_pixel_size);
+ png_row = png_malloc(png_read, png_h * sizeof(png_bytep));
+ i = 0;
+ while (i < png_h) {
+ png_row[i] = png_data + i * png_w * png_pixel_size;
+ i++;
+ }
+ if (png_bit_depth < 8)
+ png_set_packing(png_read);
+ png_read_image(png_read, png_row);
+ png_destroy_read_struct(&png_read, &png_info, NULL);
+ fclose(fp);
+ tmp.total_w = png_w;
+ tmp.total_h = png_h;
+ tmp.dim_x = dim_x;
+ tmp.dim_y = dim_y;
+ tmp.pix_w = tmp.total_w / dim_x;
+ tmp.pix_h = tmp.total_h / dim_y;
+ tmp.texture = calloc(tmp.frame_count, sizeof(GLuint));
+ if (! tmp.texture) {
+ err_puts("gl_sprite_init: tmp.texture:"
+ " failed to allocate memory");
+ str_clean(&tmp.path);
+ str_clean(&tmp.real_path);
+ return NULL;
+ }
+ assert(glGetError() == GL_NO_ERROR);
+ glGenTextures(tmp.frame_count, tmp.texture);
+ GLenum gl_error = glGetError();
+ if (gl_error != GL_NO_ERROR) {
+ err_write_1("gl_sprite_init: ");
+ err_inspect_str(&tmp.real_path);
+ err_write_1(": glGenTextures: ");
+ err_puts(gl_error_string(gl_error));
+ free(tmp.texture);
+ str_clean(&tmp.path);
+ str_clean(&tmp.real_path);
+ return NULL;
+ }
+ sprite_stride = tmp.pix_w * png_pixel_size;
+ data = malloc(tmp.pix_h * sprite_stride);
+ if (! data) {
+ err_write_1("gl_sprite_init: failed to allocate memory: ");
+ err_puts(tmp.real_path.ptr.pchar);
+ free(tmp.texture);
+ str_clean(&tmp.path);
+ str_clean(&tmp.real_path);
+ return NULL;
+ }
+ glActiveTexture(GL_TEXTURE0);
+ i = 0;
+ y = 0;
+ while (i < tmp.frame_count && y < dim_y) {
+ x = 0;
+ while (i < tmp.frame_count && x < dim_x) {
+ sprite_data = data + sprite_stride * tmp.pix_h;
+ v = 0;
+ while (v < tmp.pix_h) {
+ sprite_data -= sprite_stride;
+ memcpy(sprite_data,
+ png_row[y * tmp.pix_h + v] + x * sprite_stride,
+ sprite_stride);
+ v++;
+ }
+ glBindTexture(GL_TEXTURE_2D, tmp.texture[i]);
+ gl_error = glGetError();
+ if (gl_error != GL_NO_ERROR) {
+ err_write_1("gl_sprite_init: ");
+ err_inspect_str(&tmp.real_path);
+ err_write_1(": glBindTexture: ");
+ err_puts(gl_error_string(gl_error));
+ return NULL;
+ }
+ 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_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gl_error = glGetError();
+ if (gl_error != GL_NO_ERROR) {
+ err_write_1("gl_sprite_init: ");
+ err_inspect_str(&tmp.real_path);
+ err_write_1(": glTexParameteri: ");
+ err_puts(gl_error_string(gl_error));
+ return NULL;
+ }
+ glTexImage2D(GL_TEXTURE_2D, 0, gl_format, tmp.pix_w, tmp.pix_h,
+ 0, gl_format, gl_type, data);
+ gl_error = glGetError();
+ if (gl_error != GL_NO_ERROR) {
+ err_write_1("gl_sprite_init: ");
+ err_inspect_str(&tmp.real_path);
+ err_write_1(": glTexImage2D: ");
+ err_puts(gl_error_string(gl_error));
+ return NULL;
+ }
+ glGenerateMipmap(GL_TEXTURE_2D);
+ assert(glGetError() == GL_NO_ERROR);
+ i++;
+ x++;
+ }
+ y++;
+ }
+ glBindTexture(GL_TEXTURE_2D, 0);
+ assert(glGetError() == GL_NO_ERROR);
+ tmp.pt_w = tmp.pix_w * point_per_pixel;
+ tmp.pt_h = tmp.pix_h * point_per_pixel;
+ free(data);
+ free(png_data);
+ free(png_row);
+ *sprite = tmp;
+ return sprite;
+}
+
+GLuint gl_sprite_texture (const s_gl_sprite *sprite, uw frame)
+{
+ assert(sprite);
+ assert(frame < sprite->frame_count);
+ frame %= sprite->frame_count;
+ return sprite->texture[frame];
+}
diff --git a/window/sdl2/gl_sprite.h b/window/sdl2/gl_sprite.h
new file mode 100644
index 0000000..a436f8d
--- /dev/null
+++ b/window/sdl2/gl_sprite.h
@@ -0,0 +1,28 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 GL_SPRITE_H
+#define GL_SPRITE_H
+
+#include "types.h"
+
+/* Stack-allocation compatible functions, call gl_sprite_clean
+ after use. */
+void gl_sprite_clean (s_gl_sprite *sprite);
+s_gl_sprite * gl_sprite_init (s_gl_sprite *sprite, const char *path,
+ uw dim_x, uw dim_y, uw frame_count,
+ f32 point_per_pixel);
+
+/* Observers. */
+GLuint gl_sprite_texture (const s_gl_sprite *sprite, uw frame);
+
+#endif /* GL_SPRITE_H */
diff --git a/window/sdl2/gl_square.c b/window/sdl2/gl_square.c
new file mode 100644
index 0000000..4b511cc
--- /dev/null
+++ b/window/sdl2/gl_square.c
@@ -0,0 +1,115 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "gl_object.h"
+#include "vec3.h"
+#include "gl_square.h"
+
+void gl_square_clean (s_gl_square *square)
+{
+ assert(square);
+ gl_object_clean(&square->object);
+}
+
+void gl_square_delete (s_gl_square *square)
+{
+ assert(square);
+ gl_square_clean(square);
+ free(square);
+}
+
+s_gl_square * gl_square_init (s_gl_square *square, uw seg_u, uw seg_v)
+{
+ uw i;
+ uw j;
+ s_gl_square tmp = {0};
+ s_gl_triangle *triangle;
+ s_gl_vertex *vertex;
+ f32 y;
+ assert(square);
+ if (seg_u < 2)
+ seg_u = 2;
+ if (seg_v < 2)
+ seg_v = 2;
+ tmp.segments_u = seg_u;
+ tmp.segments_v = seg_v;
+ if (! gl_object_init(&tmp.object) ||
+ ! gl_object_allocate(&tmp.object, seg_u * seg_v,
+ 2 * (seg_u - 1) * (seg_v - 1)))
+ return NULL;
+ vertex = tmp.object.vertex.data;
+ i = 0;
+ while (i < seg_v) {
+ y = (f32) i / (seg_v - 1);
+ j = 0;
+ while (j < seg_u) {
+ vertex->tex_coord_x = vertex->pos_x = (f32) j / (seg_u - 1);
+ vertex->tex_coord_y = vertex->pos_y = y;
+ vertex->pos_z = 0.0;
+ vertex->normal_x = 0.0;
+ vertex->normal_y = 0.0;
+ vertex->normal_z = 1.0;
+ vertex++;
+ j++;
+ }
+ i++;
+ }
+ triangle = tmp.object.triangle.data;
+ i = 0;
+ while (i < seg_v - 1) {
+ j = 0;
+ while (j < seg_u - 1) {
+ triangle->a = i * seg_u + j;
+ triangle->b = (i + 1) * seg_u + j;
+ triangle->c = (i + 1) * seg_u + j + 1;
+ triangle++;
+ triangle->a = i * seg_u + j;
+ triangle->b = (i + 1) * seg_u + j + 1;
+ triangle->c = i * seg_u + j + 1;
+ triangle++;
+ j++;
+ }
+ i++;
+ }
+ gl_object_update(&tmp.object);
+ *square = tmp;
+ return square;
+}
+
+s_gl_square * gl_square_new (uw segments_u, uw segments_v)
+{
+ s_gl_square *square;
+ square = calloc(1, sizeof(s_gl_square));
+ if (! square) {
+ err_puts("gl_square_new: failed to allocate memory");
+ return NULL;
+ }
+ if (! gl_square_init(square, segments_u, segments_v)) {
+ free(square);
+ return NULL;
+ }
+ return square;
+}
+
+void gl_square_render (const s_gl_square *square)
+{
+ assert(square);
+ gl_object_render(&square->object);
+}
+
+void gl_square_render_wireframe (const s_gl_square *square)
+{
+ assert(square);
+ gl_object_render_wireframe(&square->object);
+}
diff --git a/window/sdl2/gl_square.h b/window/sdl2/gl_square.h
new file mode 100644
index 0000000..185d1cf
--- /dev/null
+++ b/window/sdl2/gl_square.h
@@ -0,0 +1,32 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 GL_SQUARE_H
+#define GL_SQUARE_H
+
+#include "types.h"
+
+/* Stack-allocation compatible functions, call gl_square_clean after
+ use. */
+void gl_square_clean (s_gl_square *square);
+s_gl_square * gl_square_init (s_gl_square *square, uw segments_u,
+ uw segments_v);
+
+/* Heap-allocation functions, call gl_square_delete after use. */
+void gl_square_delete (s_gl_square *square);
+s_gl_square * gl_square_new (uw segments_u, uw segments_v);
+
+/* Observers. */
+void gl_square_render (const s_gl_square *square);
+void gl_square_render_wireframe (const s_gl_square *square);
+
+#endif /* GL_SQUARE_H */
diff --git a/window/sdl2/gl_text.c b/window/sdl2/gl_text.c
new file mode 100644
index 0000000..3bef988
--- /dev/null
+++ b/window/sdl2/gl_text.c
@@ -0,0 +1,249 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "gl_text.h"
+#include "window_sdl2.h"
+
+void gl_text_clean (s_gl_text *text)
+{
+ str_clean(&text->str);
+ glDeleteTextures(1, &text->texture);
+}
+
+s_gl_text * gl_text_init (s_gl_text *text, const s_gl_font *font)
+{
+ s_gl_text tmp = {0};
+ assert(glGetError() == GL_NO_ERROR);
+ tmp.font = font;
+ glGenTextures(1, &tmp.texture);
+ assert(glGetError() == GL_NO_ERROR);
+ *text = tmp;
+ return text;
+}
+
+s_gl_text * gl_text_init_1 (s_gl_text *text, const s_gl_font *font,
+ const char *p)
+{
+ s_str str;
+ str_init_1(&str, NULL, p);
+ return gl_text_init_str(text, font, &str);
+}
+
+s_gl_text * gl_text_init_str (s_gl_text *text, const s_gl_font *font,
+ const s_str *str)
+{
+ s_gl_text tmp = {0};
+ if (! gl_text_init(&tmp, font))
+ return NULL;
+ if (! str_init_copy(&tmp.str, str))
+ return NULL;
+ *text = tmp;
+ return text;
+}
+
+bool gl_text_render_to_texture (s_gl_text *text)
+{
+ character c;
+ u8 *data;
+ uw data_w;
+ uw data_h;
+ u8 *data_pixel;
+ uw data_size;
+ uw data_x;
+ uw data_y;
+ FT_Vector delta;
+ FT_Face face;
+ const s_gl_font *font;
+ FT_GlyphSlot glyph;
+ FT_UInt glyph_index;
+ uw i;
+ uw j;
+ uw line_height;
+ uw max_ascent;
+ uw max_descent;
+ FT_UInt prev_glyph_index;
+ s_str s;
+ f32 scale_y;
+ uw x;
+ uw y;
+ assert(text);
+ assert(text->font);
+ assert(text->texture);
+ assert(glGetError() == GL_NO_ERROR);
+ if (! text->str.size)
+ return true;
+ glBindTexture(GL_TEXTURE_2D, text->texture);
+ assert(glGetError() == GL_NO_ERROR);
+ font = text->font;
+ face = font->ft_face;
+ s = text->str;
+ 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 = line_height;
+ x = 0;
+ prev_glyph_index = 0;
+ while (str_read_character_utf8(&s, &c) > 0) {
+ if (c == '\n') {
+ if (x > data_w)
+ data_w = x;
+ x = 0;
+ data_h += line_height;
+ prev_glyph_index = 0;
+ continue;
+ }
+ glyph_index = FT_Get_Char_Index(face, c);
+ if (prev_glyph_index && glyph_index) {
+ FT_Get_Kerning(face, prev_glyph_index, glyph_index,
+ FT_KERNING_DEFAULT, &delta);
+ x += delta.x >> 6;
+ }
+ if (FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER)) {
+ err_write_1("gl_font_render_to_texture: failed to load glyph: ");
+ err_inspect_character(&c);
+ err_write_1("\n");
+ continue;
+ }
+ glyph = face->glyph;
+ x += glyph->metrics.horiAdvance >> 6;
+ prev_glyph_index = glyph_index;
+ }
+ if (x > data_w)
+ data_w = x;
+ data_size = data_w * data_h * 4;
+ data = calloc(1, data_size);
+ x = 0;
+ y = 0;
+ prev_glyph_index = 0;
+ s = text->str;
+ while (str_read_character_utf8(&s, &c) > 0) {
+ if (c == '\n') {
+ x = 0;
+ y += line_height;
+ prev_glyph_index = 0;
+ continue;
+ }
+ glyph_index = FT_Get_Char_Index(face, c);
+ if (prev_glyph_index && glyph_index) {
+ FT_Vector delta;
+ FT_Get_Kerning(face, prev_glyph_index, glyph_index,
+ FT_KERNING_DEFAULT, &delta);
+ x += delta.x >> 6;
+ }
+ if (FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER))
+ continue;
+ glyph = face->glyph;
+ i = 0;
+ while (i < glyph->bitmap.rows) {
+ data_y = data_h - 1 - (y + i + max_ascent - glyph->bitmap_top);
+ //printf("\n");
+ j = 0;
+ while (j < glyph->bitmap.width) {
+ data_x = x + j;
+ data_pixel = data + (data_y * data_w + data_x) * 4;
+ u8 value = glyph->bitmap.buffer[i * glyph->bitmap.width + j];
+ 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]);
+ j++;
+ }
+ i++;
+ }
+ x += glyph->metrics.horiAdvance >> 6;
+ prev_glyph_index = glyph_index;
+ }
+ 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_text_set_font (s_gl_text *text, const s_gl_font *font)
+{
+ assert(text);
+ assert(font);
+ if (text->font != font) {
+ text->font = font;
+ return true;
+ }
+ return false;
+}
+
+bool gl_text_set_text (s_gl_text *text, const s_str *str)
+{
+ assert(text);
+ assert(str);
+ if (compare_str(&text->str, str)) {
+ str_clean(&text->str);
+ str_init_copy(&text->str, str);
+ return true;
+ }
+ return false;
+}
+
+bool gl_text_set_text_1 (s_gl_text *text, const char *p)
+{
+ s_str str;
+ assert(text);
+ assert(p);
+ str_init_1(&str, NULL, p);
+ return gl_text_set_text(text, &str);
+}
+
+bool gl_text_set_text_buf (s_gl_text *text, s_buf *buf)
+{
+ bool result;
+ s_str str;
+ assert(text);
+ assert(buf);
+ buf_peek_to_str(buf, &str);
+ result = gl_text_set_text(text, &str);
+ str_clean(&str);
+ return result;
+}
+
+bool gl_text_update (s_gl_text *text)
+{
+ return gl_text_render_to_texture(text);
+}
+
+bool gl_text_update_1 (s_gl_text *text, const char *p)
+{
+ if (gl_text_set_text_1(text, p)) {
+ gl_text_update(text);
+ return true;
+ }
+ return false;
+}
+
+bool gl_text_update_buf (s_gl_text *text, s_buf *buf)
+{
+ if (gl_text_set_text_buf(text, buf)) {
+ gl_text_update(text);
+ return true;
+ }
+ return false;
+}
diff --git a/window/sdl2/gl_text.h b/window/sdl2/gl_text.h
new file mode 100644
index 0000000..d4c9cd4
--- /dev/null
+++ b/window/sdl2/gl_text.h
@@ -0,0 +1,37 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 GL_TEXT_H
+#define GL_TEXT_H
+
+#include "types.h"
+
+/* Stack-allocation compatible functions, call gl_text_clean
+ after use. */
+void gl_text_clean (s_gl_text *text);
+s_gl_text * gl_text_init (s_gl_text *text, const s_gl_font *font);
+s_gl_text * gl_text_init_1 (s_gl_text *text, const s_gl_font *font,
+ const char *p);
+s_gl_text * gl_text_init_str (s_gl_text *text, const s_gl_font *font,
+ const s_str *str);
+
+/* Operators. */
+bool gl_text_render_to_texture (s_gl_text *text);
+bool gl_text_set_font (s_gl_text *text, const s_gl_font *font);
+bool gl_text_set_text (s_gl_text *text, const s_str *str);
+bool gl_text_set_text_1 (s_gl_text *text, const char *p);
+bool gl_text_set_text_buf (s_gl_text *text, s_buf *buf);
+bool gl_text_update (s_gl_text *text);
+bool gl_text_update_1 (s_gl_text *text, const char *p);
+bool gl_text_update_buf (s_gl_text *text, s_buf *buf);
+
+#endif /* GL_TEXT_H */
diff --git a/window/sdl2/gl_triangle.c b/window/sdl2/gl_triangle.c
new file mode 100644
index 0000000..0a346bd
--- /dev/null
+++ b/window/sdl2/gl_triangle.c
@@ -0,0 +1,24 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "gl_triangle.h"
+
+s_gl_triangle * gl_triangle_init (s_gl_triangle *triangle, GLuint a,
+ GLuint b, GLuint c)
+{
+ assert(triangle);
+ triangle->a = a;
+ triangle->b = b;
+ triangle->c = c;
+ return triangle;
+}
diff --git a/window/sdl2/gl_triangle.h b/window/sdl2/gl_triangle.h
new file mode 100644
index 0000000..4e0333d
--- /dev/null
+++ b/window/sdl2/gl_triangle.h
@@ -0,0 +1,21 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 GL_TRIANGLE_H
+#define GL_TRIANGLE_H
+
+#include "types.h"
+
+s_gl_triangle * gl_triangle_init (s_gl_triangle *triangle, GLuint a,
+ GLuint b, GLuint c);
+
+#endif /* GL_TRIANGLE_H */
diff --git a/window/sdl2/gl_vertex.c b/window/sdl2/gl_vertex.c
new file mode 100644
index 0000000..ea82997
--- /dev/null
+++ b/window/sdl2/gl_vertex.c
@@ -0,0 +1,47 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "mat4.h"
+#include "vec3.h"
+#include "gl_vertex.h"
+
+void gl_vertex_attrib (void)
+{
+ assert(glGetError() == GL_NO_ERROR);
+ glEnableVertexAttribArray(0);
+ assert(glGetError() == GL_NO_ERROR);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(s_gl_vertex),
+ (void *) 0);
+ assert(glGetError() == GL_NO_ERROR);
+ glEnableVertexAttribArray(1);
+ assert(glGetError() == GL_NO_ERROR);
+ glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(s_gl_vertex),
+ (void *) (3 * sizeof(float)));
+ assert(glGetError() == GL_NO_ERROR);
+ glEnableVertexAttribArray(2);
+ assert(glGetError() == GL_NO_ERROR);
+ glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(s_gl_vertex),
+ (void *) (6 * sizeof(float)));
+ assert(glGetError() == GL_NO_ERROR);
+}
+
+void gl_vertex_transform (s_gl_vertex *vertex, const s_mat4 *matrix)
+{
+ assert(vertex);
+ assert(matrix);
+ mat4_mult_vec3(matrix, (s_vec3 *) &vertex->pos_x,
+ (s_vec3 *) &vertex->pos_x);
+ mat4_mult_vec3(matrix, (s_vec3 *) &vertex->normal_x,
+ (s_vec3 *) &vertex->normal_x);
+ vec3_normalize((s_vec3 *) &vertex->normal_x);
+}
diff --git a/window/sdl2/gl_vertex.h b/window/sdl2/gl_vertex.h
new file mode 100644
index 0000000..7206048
--- /dev/null
+++ b/window/sdl2/gl_vertex.h
@@ -0,0 +1,21 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 GL_VERTEX_H
+#define GL_VERTEX_H
+
+#include "types.h"
+
+void gl_vertex_attrib (void);
+void gl_vertex_transform (s_gl_vertex *vertex, const s_mat4 *matrix);
+
+#endif /* GL_VERTEX_H */
diff --git a/window/sdl2/gl_vtext.c b/window/sdl2/gl_vtext.c
new file mode 100644
index 0000000..3927976
--- /dev/null
+++ b/window/sdl2/gl_vtext.c
@@ -0,0 +1,403 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "gl_vtext.h"
+
+void gl_vtext_clean (s_gl_text *text)
+{
+ assert(text);
+ str_clean(&text->str);
+ glDeleteTextures(1, &text->texture);
+}
+
+void gl_vtext_delete (s_gl_text *text)
+{
+ gl_vtext_clean(text);
+ free(text);
+}
+
+s_gl_text * gl_vtext_init (s_gl_text *text, const s_gl_font *font)
+{
+ s_gl_text tmp = {0};
+ assert(glGetError() == GL_NO_ERROR);
+ tmp.font = font;
+ glGenTextures(1, &tmp.texture);
+ assert(glGetError() == GL_NO_ERROR);
+ *text = tmp;
+ return text;
+}
+
+s_gl_text * gl_vtext_init_1 (s_gl_text *text, const s_gl_font *font,
+ const char *p)
+{
+ s_str str;
+ str_init_1(&str, NULL, p);
+ return gl_vtext_init_str(text, font, &str);
+}
+
+s_gl_text * gl_vtext_init_str (s_gl_text *text, const s_gl_font *font,
+ const s_str *str)
+{
+ s_gl_text tmp = {0};
+ if (! gl_vtext_init(&tmp, font))
+ return NULL;
+ if (! str_init_copy(&tmp.str, str))
+ return NULL;
+ *text = tmp;
+ 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;
+ text = calloc(1, sizeof(s_gl_text));
+ if (! text) {
+ err_puts("gl_vtext_new_1: failed to allocate memory");
+ assert(! "gl_vtext_new_1: failed to allocate memory");
+ return NULL;
+ }
+ if (! gl_vtext_init_1(text, font, p)) {
+ free(text);
+ return NULL;
+ }
+ return text;
+}
+
+s_gl_text * gl_vtext_new_str (const s_gl_font *font, const s_str *str)
+{
+ s_gl_text *text;
+ text = calloc(1, sizeof(s_gl_text));
+ if (! text) {
+ err_puts("gl_vtext_new_1: failed to allocate memory");
+ assert(! "gl_vtext_new_1: failed to allocate memory");
+ return NULL;
+ }
+ if (! gl_vtext_init_str(text, font, str)) {
+ free(text);
+ return NULL;
+ }
+ return text;
+}
+
+bool gl_vtext_render_to_texture (s_gl_text *text)
+{
+ character c;
+ 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 line_height;
+ uw max_ascent;
+ uw max_descent;
+ s_str s;
+ f32 scale_y;
+ uw x;
+ uw y;
+ assert(text);
+ assert(text->font);
+ assert(text->texture);
+ assert(glGetError() == GL_NO_ERROR);
+ if (! text->str.size)
+ return true;
+ glBindTexture(GL_TEXTURE_2D, text->texture);
+ assert(glGetError() == GL_NO_ERROR);
+ font = text->font;
+ face = font->ft_face;
+ s = text->str;
+ 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;
+ while (str_read_character_utf8(&s, &c) > 0) {
+ glyph_index = FT_Get_Char_Index(face, c);
+ if (FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER)) {
+ err_write_1("gl_font_render_to_texture: failed to load glyph: ");
+ err_inspect_character(&c);
+ 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;
+ s = text->str;
+ while (str_read_character_utf8(&s, &c) > 0) {
+ glyph_index = FT_Get_Char_Index(face, c);
+ if (FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER))
+ continue;
+ glyph = face->glyph;
+ x = (data_w - (glyph->metrics.width >> 6)) / 2;
+ i = 0;
+ while (i < glyph->bitmap.rows) {
+ data_y = data_h - line_height - 1 - (y + i + max_ascent - glyph->bitmap_top);
+ //printf("\n");
+ j = 0;
+ while (j < glyph->bitmap.width) {
+ data_x = x + j;
+ data_pixel = data + (data_y * data_w + data_x) * 4;
+ u8 value = glyph->bitmap.buffer[i * glyph->bitmap.width + j];
+ 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]);
+ j++;
+ }
+ i++;
+ }
+ 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_render_to_texture_random (s_gl_text *text, uw len)
+{
+ FT_UInt *glyphs;
+ u8 *data;
+ sw data_w;
+ sw data_h;
+ u8 *data_pixel;
+ sw data_size;
+ sw data_x;
+ sw data_y;
+ FT_Face face;
+ const s_gl_font *font;
+ FT_GlyphSlot glyph;
+ FT_UInt glyph_index;
+ sw i;
+ uw j;
+ uw k;
+ sw line_height;
+ sw max_ascent;
+ sw max_descent;
+ f32 scale_y;
+ sw x;
+ sw 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 (glyphs)");
+ assert(! "gl_vtext_render_to_texture_random:"
+ " failed to allocate memory (glyphs)");
+ return false;
+ }
+ for (i = 0; i < (sw) len; i++) {
+ glyph = NULL;
+ 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 >> 6);
+ } while (! glyph || ! (glyph->metrics.width >> 6));
+ }
+ 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 < (sw) 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_w++;
+ data_h += line_height * 2;
+ data_size = data_w * data_h * 4;
+ data = calloc(1, data_size);
+ if (! data) {
+ err_puts("gl_vtext_render_to_texture_random:"
+ " failed to allocate memory (data)");
+ assert(! "gl_vtext_render_to_texture_random:"
+ " failed to allocate memory (data)");
+ free(glyphs);
+ return false;
+ }
+ x = 0;
+ y = 0;
+ for (i = 0; i < (sw) 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 - line_height - 1 -
+ ((sw) 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;
+ }
+ free(glyphs);
+ 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);
+ assert(font);
+ if (text->font != font) {
+ text->font = font;
+ return true;
+ }
+ return false;
+}
+
+bool gl_vtext_set_text (s_gl_text *text, const s_str *str)
+{
+ assert(text);
+ assert(str);
+ if (compare_str(&text->str, str)) {
+ str_clean(&text->str);
+ str_init_copy(&text->str, str);
+ return true;
+ }
+ return false;
+}
+
+bool gl_vtext_set_text_1 (s_gl_text *text, const char *p)
+{
+ s_str str;
+ assert(text);
+ assert(p);
+ str_init_1(&str, NULL, p);
+ return gl_vtext_set_text(text, &str);
+}
+
+bool gl_vtext_set_text_buf (s_gl_text *text, s_buf *buf)
+{
+ bool result;
+ s_str str;
+ assert(text);
+ assert(buf);
+ buf_peek_to_str(buf, &str);
+ result = gl_vtext_set_text(text, &str);
+ str_clean(&str);
+ return result;
+}
+
+bool gl_vtext_update (s_gl_text *text)
+{
+ return gl_vtext_render_to_texture(text);
+}
+
+bool gl_vtext_update_1 (s_gl_text *text, const char *p)
+{
+ if (gl_vtext_set_text_1(text, p)) {
+ gl_vtext_update(text);
+ return true;
+ }
+ return false;
+}
+
+bool gl_vtext_update_buf (s_gl_text *text, s_buf *buf)
+{
+ if (gl_vtext_set_text_buf(text, buf)) {
+ gl_vtext_update(text);
+ return true;
+ }
+ return false;
+}
diff --git a/window/sdl2/gl_vtext.h b/window/sdl2/gl_vtext.h
new file mode 100644
index 0000000..82d67d7
--- /dev/null
+++ b/window/sdl2/gl_vtext.h
@@ -0,0 +1,44 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 GL_VTEXT_H
+#define GL_VTEXT_H
+
+#include "types.h"
+
+/* Stack-allocation compatible functions, call gl_vtext_clean
+ after use. */
+void gl_vtext_clean (s_gl_text *text);
+s_gl_text * gl_vtext_init (s_gl_text *text, const s_gl_font *font);
+s_gl_text * gl_vtext_init_1 (s_gl_text *text, const s_gl_font *font,
+ const char *p);
+s_gl_text * gl_vtext_init_str (s_gl_text *text, const s_gl_font *font,
+ const s_str *str);
+
+/* 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);
+bool gl_vtext_set_text_buf (s_gl_text *text, s_buf *buf);
+bool gl_vtext_update (s_gl_text *text);
+bool gl_vtext_update_1 (s_gl_text *text, const char *p);
+bool gl_vtext_update_buf (s_gl_text *text, s_buf *buf);
+
+#endif /* GL_TEXT_H */
diff --git a/window/sdl2/mat3.h b/window/sdl2/mat3.h
new file mode 100644
index 0000000..a48b057
--- /dev/null
+++ b/window/sdl2/mat3.h
@@ -0,0 +1,35 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 MAT3_H
+#define MAT3_H
+
+#include "types.h"
+
+/* Stack-allocation compatible functions. */
+s_mat3 * mat3_init_copy (s_mat3 *m, const s_mat3 *src);
+s_mat3 * mat3_init_identity (s_mat3 *m);
+s_mat3 * mat3_init_matrix_mult (s_mat3 *m, const s_mat3 *a,
+ const s_mat3 *b);
+
+/* Heap-allocation functions, call mat3_delete after use. */
+void mat3_delete (s_mat3 *m);
+s_mat3 * mat3_new_copy (const s_mat3 *src);
+s_mat3 * mat3_new_identity (void);
+s_mat3 * mat3_new_matrix_mult (const s_mat3 *a, const s_mat3 *b);
+
+/* Operators. */
+s_mat3 * mat3_rotate (s_mat3 *m, f32 rad);
+s_mat3 * mat3_scale (s_mat3 *m, f32 x, f32 y);
+s_mat3 * mat3_translate (s_mat3 *m, f32 x, f32 y);
+
+#endif /* MAT3_H */
diff --git a/window/sdl2/mat4.c b/window/sdl2/mat4.c
new file mode 100644
index 0000000..3272eb8
--- /dev/null
+++ b/window/sdl2/mat4.c
@@ -0,0 +1,293 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "mat4.h"
+#include "vec3.h"
+
+sw mat4_buf_inspect (s_buf *buf, const s_mat4 *matrix)
+{
+ u8 i;
+ u8 j;
+ sw r;
+ sw result = 0;
+ assert(buf);
+ assert(matrix);
+ const f32 *m;
+ if ((r = buf_write_1(buf, "(F32) {")) < 0)
+ return r;
+ result += r;
+ m = &matrix->xx;
+ i = 0;
+ while (i < 4) {
+ j = 0;
+ while (j < 4) {
+ if ((r = buf_inspect_f32(buf, m + j * 4 + i)) < 0)
+ return r;
+ result += r;
+ if (i < 3 || j < 3) {
+ if ((r = buf_write_1(buf, ",")) < 0)
+ return r;
+ result += r;
+ if (j < 3) {
+ if ((r = buf_write_1(buf, " ")) < 0)
+ return r;
+ result += r;
+ }
+ }
+ j++;
+ }
+ if (i < 3) {
+ if ((r = buf_write_1(buf, "\n ")) < 0)
+ return r;
+ result += r;
+ }
+ i++;
+ }
+ if ((r = buf_write_1(buf, "}\n")) < 0)
+ return r;
+ result += r;
+ return result;
+}
+
+s_mat4 * mat4_init_copy (s_mat4 *m, const s_mat4 *src)
+{
+ assert(m);
+ assert(src);
+ *m = *src;
+ return m;
+}
+
+s_mat4 * mat4_init_ortho (s_mat4 *m, f32 x1, f32 x2, f32 y1, f32 y2,
+ f32 clip_z_near, f32 clip_z_far)
+{
+ f32 dx;
+ f32 dy;
+ f32 dz;
+ s_mat4 ortho;
+ assert(m);
+ dx = x2 - x1;
+ dy = y2 - y1;
+ dz = clip_z_far - clip_z_near;
+ mat4_init_zero(&ortho);
+ ortho.xx = 2.0 / dx;
+ ortho.yy = 2.0 / dy;
+ ortho.zz = -2.0 / dz;
+ ortho.tx = - (x1 + x2) / dx;
+ ortho.ty = - (y1 + y2) / dy;
+ ortho.tz = - (clip_z_near + clip_z_far) / dz;
+ ortho.tt = 1.0;
+ *m = ortho;
+ return m;
+}
+
+s_mat4 * mat4_init_product (s_mat4 *m, const s_mat4 *a, const s_mat4 *b)
+{
+ assert(m);
+ assert(a);
+ assert(b);
+ m->xx = a->xx * b->xx + a->xy * b->yx + a->xz * b->zx + a->xt * b->tx;
+ m->xy = a->xx * b->xy + a->xy * b->yy + a->xz * b->zy + a->xt * b->ty;
+ m->xz = a->xx * b->xz + a->xy * b->yz + a->xz * b->zz + a->xt * b->tz;
+ m->xt = a->xx * b->xt + a->xy * b->yt + a->xz * b->zt + a->xt * b->tt;
+ m->yx = a->yx * b->xx + a->yy * b->yx + a->yz * b->zx + a->yt * b->tx;
+ m->yy = a->yx * b->xy + a->yy * b->yy + a->yz * b->zy + a->yt * b->ty;
+ m->yz = a->yx * b->xz + a->yy * b->yz + a->yz * b->zz + a->yt * b->tz;
+ m->yt = a->yx * b->xt + a->yy * b->yt + a->yz * b->zt + a->yt * b->tt;
+ m->zx = a->zx * b->xx + a->zy * b->yx + a->zz * b->zx + a->zt * b->tx;
+ m->zy = a->zx * b->xy + a->zy * b->yy + a->zz * b->zy + a->zt * b->ty;
+ m->zz = a->zx * b->xz + a->zy * b->yz + a->zz * b->zz + a->zt * b->tz;
+ m->zt = a->zx * b->xt + a->zy * b->yt + a->zz * b->zt + a->zt * b->tt;
+ m->tx = a->tx * b->xx + a->ty * b->yx + a->tz * b->zx + a->tt * b->tx;
+ m->ty = a->tx * b->xy + a->ty * b->yy + a->tz * b->zy + a->tt * b->ty;
+ m->tz = a->tx * b->xz + a->ty * b->yz + a->tz * b->zz + a->tt * b->tz;
+ m->tt = a->tx * b->xt + a->ty * b->yt + a->tz * b->zt + a->tt * b->tt;
+ return m;
+}
+
+s_mat4 * mat4_init_identity (s_mat4 *m)
+{
+ assert(m);
+ m->xx = 1.0; m->xy = 0.0; m->xz = 0.0; m->xt = 0.0;
+ m->yx = 0.0; m->yy = 1.0; m->yz = 0.0; m->yt = 0.0;
+ m->zx = 0.0; m->zy = 0.0; m->zz = 1.0; m->zt = 0.0;
+ m->tx = 0.0; m->ty = 0.0; m->tz = 0.0; m->tt = 1.0;
+ return m;
+}
+
+s_mat4 * mat4_init_scale (s_mat4 *m, f32 x, f32 y, f32 z)
+{
+ assert(m);
+ m->xx = x; m->xy = 0.0; m->xz = 0.0; m->xt = 0.0;
+ m->yx = 0.0; m->yy = y; m->yz = 0.0; m->yt = 0.0;
+ m->zx = 0.0; m->zy = 0.0; m->zz = z; m->zt = 0.0;
+ m->tx = 0.0; m->ty = 0.0; m->tz = 0.0; m->tt = 1.0;
+ return m;
+}
+
+s_mat4 * mat4_init_zero (s_mat4 *m)
+{
+ assert(m);
+ m->xx = 0.0; m->xy = 0.0; m->xz = 0.0; m->xt = 0.0;
+ m->yx = 0.0; m->yy = 0.0; m->yz = 0.0; m->yt = 0.0;
+ m->zx = 0.0; m->zy = 0.0; m->zz = 0.0; m->zt = 0.0;
+ m->tx = 0.0; m->ty = 0.0; m->tz = 0.0; m->tt = 0.0;
+ return m;
+}
+
+void mat4_delete (s_mat4 *m)
+{
+ free(m);
+}
+
+s_mat4 * mat4_new_copy (const s_mat4 *src)
+{
+ s_mat4 *m;
+ m = calloc(1, sizeof(s_mat4));
+ if (! m) {
+ err_puts("mat4_new: failed to allocate memory");
+ return NULL;
+ }
+ *m = *src;
+ return m;
+}
+
+s_mat4 * mat4_new_product (const s_mat4 *a, const s_mat4 *b)
+{
+ s_mat4 *m;
+ assert(a);
+ assert(b);
+ m = calloc(1, sizeof(s_mat4));
+ if (! m) {
+ err_puts("mat4_new: failed to allocate memory");
+ return NULL;
+ }
+ mat4_init_product(m, a, b);
+ return m;
+}
+
+s_mat4 * mat4_new_zero (void)
+{
+ s_mat4 *m;
+ m = calloc(1, sizeof(s_mat4));
+ if (! m) {
+ err_puts("mat4_new: failed to allocate memory");
+ return NULL;
+ }
+ mat4_init_zero(m);
+ return m;
+}
+
+s_mat4 * mat4_ortho (s_mat4 *m, f32 x1, f32 x2, f32 y1, f32 y2,
+ f32 clip_z_near, f32 clip_z_far)
+{
+ s_mat4 ortho;
+ assert(m);
+ mat4_init_ortho(&ortho, x1, x2, y1, y2, clip_z_near, clip_z_far);
+ return mat4_mult_mat4(&ortho, m, m);
+}
+
+s_mat4 * mat4_perspective (s_mat4 *m, f32 fov_y,
+ f32 aspect_ratio,
+ f32 z_near,
+ f32 z_far)
+{
+ f32 dz;
+ s_mat4 perspective;
+ f32 f;
+ f32 fov_y_2;
+ fov_y_2 = fov_y / 2.0;
+ f = cos(fov_y_2) / sin(fov_y_2);
+ dz = z_near - z_far;
+ mat4_init_zero(&perspective);
+ perspective.xx = f / aspect_ratio;
+ perspective.yy = f;
+ perspective.zz = (z_near + z_far) / dz;
+ perspective.zt = -1.0;
+ perspective.tz = 2.0 * z_near * z_far / dz;
+ return mat4_mult_mat4(&perspective, m, m);
+}
+
+s_mat4 * mat4_mult_mat4 (const s_mat4 *a, const s_mat4 *b, s_mat4 *dest)
+{
+ s_mat4 m;
+ assert(a);
+ assert(b);
+ m.xx = a->xx * b->xx + a->xy * b->yx + a->xz * b->zx + a->xt * b->tx;
+ m.xy = a->xx * b->xy + a->xy * b->yy + a->xz * b->zy + a->xt * b->ty;
+ m.xz = a->xx * b->xz + a->xy * b->yz + a->xz * b->zz + a->xt * b->tz;
+ m.xt = a->xx * b->xt + a->xy * b->yt + a->xz * b->zt + a->xt * b->tt;
+ m.yx = a->yx * b->xx + a->yy * b->yx + a->yz * b->zx + a->yt * b->tx;
+ m.yy = a->yx * b->xy + a->yy * b->yy + a->yz * b->zy + a->yt * b->ty;
+ m.yz = a->yx * b->xz + a->yy * b->yz + a->yz * b->zz + a->yt * b->tz;
+ m.yt = a->yx * b->xt + a->yy * b->yt + a->yz * b->zt + a->yt * b->tt;
+ m.zx = a->zx * b->xx + a->zy * b->yx + a->zz * b->zx + a->zt * b->tx;
+ m.zy = a->zx * b->xy + a->zy * b->yy + a->zz * b->zy + a->zt * b->ty;
+ m.zz = a->zx * b->xz + a->zy * b->yz + a->zz * b->zz + a->zt * b->tz;
+ m.zt = a->zx * b->xt + a->zy * b->yt + a->zz * b->zt + a->zt * b->tt;
+ m.tx = a->tx * b->xx + a->ty * b->yx + a->tz * b->zx + a->tt * b->tx;
+ m.ty = a->tx * b->xy + a->ty * b->yy + a->tz * b->zy + a->tt * b->ty;
+ m.tz = a->tx * b->xz + a->ty * b->yz + a->tz * b->zz + a->tt * b->tz;
+ m.tt = a->tx * b->xt + a->ty * b->yt + a->tz * b->zt + a->tt * b->tt;
+ *dest = m;
+ return dest;
+}
+
+s_mat4 * mat4_scale (s_mat4 *m, f32 x, f32 y, f32 z)
+{
+ s_mat4 s;
+ mat4_init_zero(&s);
+ s.xx = x;
+ s.yy = y;
+ s.zz = z;
+ s.tt = 1.0;
+ return mat4_mult_mat4(&s, m, m);
+}
+
+s_mat4 * mat4_translate (s_mat4 *m, f32 x, f32 y, f32 z)
+{
+ s_mat4 s;
+ mat4_init_identity(&s);
+ s.tx = x;
+ s.ty = y;
+ s.tz = z;
+ return mat4_mult_mat4(&s, m, m);
+}
+
+s_mat4 * mat4_rotate_axis (s_mat4 *m, f32 rad, const s_vec3 *axis)
+{
+ s_vec3 a;
+ f32 angle;
+ f32 one_minus_x;
+ f32 x;
+ f32 y;
+ vec3_init_normalize(&a, axis);
+ angle = -rad;
+ x = cosf(angle);
+ one_minus_x = 1.0 - x;
+ y = sinf(angle);
+ s_mat4 r = { x + a.x * a.x * one_minus_x,
+ a.x * a.y * one_minus_x - a.z * y,
+ a.x * a.z * one_minus_x + a.y * y,
+ 0.0,
+ a.x * a.y * one_minus_x + a.z * y,
+ x + a.y * a.y * one_minus_x,
+ a.y * a.z * one_minus_x - a.x * y,
+ 0.0,
+ a.x * a.z * one_minus_x - a.y * y,
+ a.y * a.z * one_minus_x + a.x * y,
+ x + a.z * a.z * one_minus_x,
+ 0.0,
+ 0.0, 0.0, 0.0, 1.0 };
+ return mat4_mult_mat4(&r, m, m);
+}
diff --git a/window/sdl2/mat4.h b/window/sdl2/mat4.h
new file mode 100644
index 0000000..00fedf1
--- /dev/null
+++ b/window/sdl2/mat4.h
@@ -0,0 +1,47 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 MAT4_H
+#define MAT4_H
+
+#include "types.h"
+
+/* Stack-allocation compatible functions. */
+s_mat4 * mat4_init_copy (s_mat4 *m, const s_mat4 *src);
+s_mat4 * mat4_init_identity (s_mat4 *m);
+s_mat4 * mat4_init_product (s_mat4 *m, const s_mat4 *a,
+ const s_mat4 *b);
+s_mat4 * mat4_init_scale (s_mat4 *m, f32 x, f32 y, f32 z);
+s_mat4 * mat4_init_zero (s_mat4 *m);
+
+/* Heap-allocation functions, call mat4_delete after use. */
+void mat4_delete (s_mat4 *m);
+s_mat4 * mat4_new_copy (const s_mat4 *src);
+s_mat4 * mat4_new_identity (void);
+s_mat4 * mat4_new_matrix_mult (const s_mat4 *a, const s_mat4 *b);
+s_mat4 * mat4_new_zero (void);
+
+/* Operators. */
+s_mat4 * mat4_mult_mat4 (const s_mat4 *a, const s_mat4 *b, s_mat4 *dest);
+s_vec3 * mat4_mult_vec3 (const s_mat4 *a, const s_vec3 *b, s_vec3 *dest);
+s_mat4 * mat4_ortho (s_mat4 *m, f32 x1, f32 x2, f32 y1, f32 y2,
+ f32 clip_z_near, f32 clip_z_far);
+s_mat4 * mat4_perspective (s_mat4 *m, f32 fov_y, f32 aspect_ratio,
+ f32 clip_z_near, f32 clip_z_far);
+s_mat4 * mat4_rotate_axis (s_mat4 *m, f32 rad, const s_vec3 *axis);
+s_mat4 * mat4_scale (s_mat4 *m, f32 x, f32 y, f32 z);
+s_mat4 * mat4_translate (s_mat4 *m, f32 x, f32 y, f32 z);
+
+/* Observers. */
+sw mat4_buf_inspect (s_buf *buf, const s_mat4 *matrix);
+
+#endif /* MAT4_H */
diff --git a/window/sdl2/sources.mk b/window/sdl2/sources.mk
new file mode 100644
index 0000000..bb0e664
--- /dev/null
+++ b/window/sdl2/sources.mk
@@ -0,0 +1,50 @@
+# sources.mk generated by update_sources
+HEADERS = \
+ "dmat3.h" \
+ "dmat4.h" \
+ "dvec2.h" \
+ "dvec3.h" \
+ "gl_camera.h" \
+ "gl_cylinder.h" \
+ "gl_deprecated.h" \
+ "gl_font.h" \
+ "gl_lines.h" \
+ "gl_object.h" \
+ "gl_ortho.h" \
+ "gl_sphere.h" \
+ "gl_sprite.h" \
+ "gl_square.h" \
+ "gl_text.h" \
+ "gl_triangle.h" \
+ "gl_vertex.h" \
+ "gl_vtext.h" \
+ "mat3.h" \
+ "mat4.h" \
+ "types.h" \
+ "vec2.h" \
+ "vec3.h" \
+ "window_sdl2.h" \
+
+SOURCES = \
+ "dmat4.c" \
+ "dvec2.c" \
+ "dvec3.c" \
+ "gl_camera.c" \
+ "gl_cylinder.c" \
+ "gl_deprecated.c" \
+ "gl_font.c" \
+ "gl_lines.c" \
+ "gl_object.c" \
+ "gl_ortho.c" \
+ "gl_sphere.c" \
+ "gl_sprite.c" \
+ "gl_square.c" \
+ "gl_text.c" \
+ "gl_triangle.c" \
+ "gl_vertex.c" \
+ "gl_vtext.c" \
+ "mat4.c" \
+ "vec2.c" \
+ "vec3.c" \
+ "window_sdl2.c" \
+
diff --git a/window/sdl2/sources.sh b/window/sdl2/sources.sh
new file mode 100644
index 0000000..9c93345
--- /dev/null
+++ b/window/sdl2/sources.sh
@@ -0,0 +1,3 @@
+# sources.sh generated by update_sources
+HEADERS='dmat3.h dmat4.h dvec2.h dvec3.h gl_camera.h gl_cylinder.h gl_deprecated.h gl_font.h gl_lines.h gl_object.h gl_ortho.h gl_sphere.h gl_sprite.h gl_square.h gl_text.h gl_triangle.h gl_vertex.h gl_vtext.h mat3.h mat4.h types.h vec2.h vec3.h window_sdl2.h '
+SOURCES='dmat4.c dvec2.c dvec3.c gl_camera.c gl_cylinder.c gl_deprecated.c gl_font.c gl_lines.c gl_object.c gl_ortho.c gl_sphere.c gl_sprite.c gl_square.c gl_text.c gl_triangle.c gl_vertex.c gl_vtext.c mat4.c vec2.c vec3.c window_sdl2.c '
diff --git a/window/sdl2/types.h b/window/sdl2/types.h
new file mode 100644
index 0000000..6b6952e
--- /dev/null
+++ b/window/sdl2/types.h
@@ -0,0 +1,396 @@
+/* kc3
+ * Copyright 2022,2023,2024 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.
+ */
+/** @file types.h
+ * @brief Module KC3.Window.SDL2
+ *
+ * Struct for all GUI window SDL2 graphics operations.
+ */
+#ifndef LIBKC3_WINDOW_SDL2_TYPES_H
+#define LIBKC3_WINDOW_SDL2_TYPES_H
+
+#include <GL/glew.h>
+#include <SDL.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include <png.h>
+#include <libkc3/types.h>
+#include "../types.h"
+
+#define GL_CAMERA_LIGHT_MAX 16 // keep in sync with shader
+
+typedef struct dmat3 s_dmat3;
+typedef struct dmat4 s_dmat4;
+typedef struct dvec2 s_dvec2;
+typedef struct dvec3 s_dvec3;
+typedef struct dvec4 s_dvec4;
+typedef struct gl_camera s_gl_camera;
+typedef struct gl_cylinder s_gl_cylinder;
+typedef struct gl_font s_gl_font;
+typedef struct gl_light s_gl_light;
+typedef struct gl_lines s_gl_lines;
+typedef struct gl_material s_gl_material;
+typedef struct gl_object s_gl_object;
+typedef struct gl_ortho s_gl_ortho;
+typedef struct gl_sphere s_gl_sphere;
+typedef struct gl_sprite s_gl_sprite;
+typedef struct gl_square s_gl_square;
+typedef struct gl_text s_gl_text;
+typedef struct gl_triangle s_gl_triangle;
+typedef struct gl_vertex s_gl_vertex;
+typedef struct mat3 s_mat3;
+typedef struct mat4 s_mat4;
+typedef struct rgb s_rgb;
+typedef struct rgba s_rgba;
+typedef struct vec2 s_vec2;
+typedef struct vec3 s_vec3;
+typedef struct vec4 s_vec4;
+typedef struct window_sdl2 s_window_sdl2;
+
+/* return false to break event loop */
+typedef bool (*f_window_sdl2_button) (s_window_sdl2 *window,
+ u8 button, sw x, sw y);
+
+/* return false to break event loop */
+typedef bool (*f_window_sdl2_key) (s_window_sdl2 *window,
+ SDL_Keysym *keysym);
+
+/* return false to break event loop */
+typedef bool (*f_window_sdl2_load) (s_window_sdl2 *window);
+
+/* return false to break event loop */
+typedef bool (*f_window_sdl2_motion) (s_window_sdl2 *window, sw x,
+ sw y);
+
+/* return false to break event loop */
+typedef bool (*f_window_sdl2_render) (s_window_sdl2 *window);
+
+/* return false to break event loop */
+typedef bool (*f_window_sdl2_resize) (s_window_sdl2 *window,
+ uw w, uw h);
+
+typedef bool (*f_window_sdl2_sequence_load) (s_sequence *seq,
+ s_window_sdl2 *window);
+
+typedef bool (*f_window_sdl2_sequence_render) (s_sequence *seq,
+ s_window_sdl2 *window,
+ void *context);
+
+typedef void (*f_window_sdl2_unload) (s_window_sdl2 *window);
+
+/* 1 */
+
+struct dmat3 {
+ f64 xx;
+ f64 yx;
+ f64 zx;
+ f64 xy;
+ f64 yy;
+ f64 zy;
+ f64 xz;
+ f64 yz;
+ f64 zz;
+};
+
+struct dmat4 {
+ f64 xx;
+ f64 xy;
+ f64 xz;
+ f64 xt;
+ f64 yx;
+ f64 yy;
+ f64 yz;
+ f64 yt;
+ f64 zx;
+ f64 zy;
+ f64 zz;
+ f64 zt;
+ f64 tx;
+ f64 ty;
+ f64 tz;
+ f64 tt;
+};
+
+struct dvec2 {
+ f64 x;
+ f64 y;
+};
+
+struct dvec3 {
+ f64 x;
+ f64 y;
+ f64 z;
+};
+
+struct dvec4 {
+ f64 x;
+ f64 y;
+ f64 z;
+ f64 t;
+};
+
+struct gl_font {
+ FT_Face ft_face;
+ s_str path;
+ f32 point_size;
+ f32 point_per_pixel;
+ s_str real_path;
+};
+
+struct gl_lines {
+ s_array vertex;
+ GLuint gl_vao;
+ GLuint gl_vbo;
+};
+
+struct mat3 {
+ f32 xx;
+ f32 yx;
+ f32 zx;
+ f32 xy;
+ f32 yy;
+ f32 zy;
+ f32 xz;
+ f32 yz;
+ f32 zz;
+};
+
+struct mat4 {
+ f32 xx;
+ f32 xy;
+ f32 xz;
+ f32 xt;
+ f32 yx;
+ f32 yy;
+ f32 yz;
+ f32 yt;
+ f32 zx;
+ f32 zy;
+ f32 zz;
+ f32 zt;
+ f32 tx;
+ f32 ty;
+ f32 tz;
+ f32 tt;
+};
+
+struct gl_object {
+ s_array vertex;
+ s_array triangle;
+ u32 gl_mode;
+ u32 gl_vao;
+ u32 gl_vbo;
+ u32 gl_ebo;
+};
+
+struct gl_sprite {
+ uw dim_x;
+ uw dim_y;
+ uw frame_count;
+ s_str path;
+ uw pix_w;
+ uw pix_h;
+ f32 pt_w;
+ f32 pt_h;
+ s_str real_path;
+ GLuint *texture;
+ uw total_w;
+ uw total_h;
+};
+
+struct gl_text {
+ const s_gl_font *font;
+ uw pix_w;
+ uw pix_h;
+ f32 pt_w;
+ f32 pt_h;
+ s_str str;
+ GLuint texture;
+};
+
+struct gl_triangle {
+ GLuint a;
+ GLuint b;
+ GLuint c;
+};
+
+struct rgb {
+ f32 r;
+ f32 g;
+ f32 b;
+};
+
+struct rgba {
+ f32 r;
+ f32 g;
+ f32 b;
+ f32 a;
+};
+
+struct vec2 {
+ f32 x;
+ f32 y;
+};
+
+struct vec3 {
+ f32 x;
+ f32 y;
+ f32 z;
+};
+
+struct vec4 {
+ f32 x;
+ f32 y;
+ f32 z;
+ f32 t;
+};
+
+/* Subtype of s_window. See libkc3/window/types.h */
+struct window_sdl2 {
+ sw x;
+ sw y;
+ uw w;
+ uw h;
+ bool fullscreen;
+ f_window_sdl2_button button;
+ f_window_sdl2_key key;
+ f_window_sdl2_load load;
+ f_window_sdl2_motion motion;
+ f_window_sdl2_render render;
+ SDL_Window *sdl_window;
+ f_window_sdl2_resize resize;
+ s_sequence *seq;
+ s_sequence *sequence;
+ uw sequence_count;
+ uw sequence_pos;
+ s_tag tag; // TODO: move sequence to tag
+ const char *title;
+ f_window_sdl2_unload unload;
+ uw gl_w;
+ uw gl_h;
+ float dpi;
+ float dpi_w;
+ float dpi_h;
+};
+
+/* 2 */
+
+struct gl_cylinder {
+ s_gl_object object;
+ uw segments_u;
+ uw segments_v;
+};
+
+struct gl_light {
+ s_vec4 position; // in camera coordinates
+ s_rgb intensity;
+};
+
+struct gl_material {
+ f32 roughness;
+ bool metal;
+ s_rgba color;
+};
+
+struct gl_sphere {
+ s_gl_object object;
+ uw segments_u;
+ uw segments_v;
+};
+
+struct gl_square {
+ s_gl_object object;
+ uw segments_u;
+ uw segments_v;
+};
+
+struct gl_vertex {
+ f32 pos_x;
+ f32 pos_y;
+ f32 pos_z;
+ f32 normal_x;
+ f32 normal_y;
+ f32 normal_z;
+ f32 tex_coord_x;
+ f32 tex_coord_y;
+};
+
+struct sdl2_sprite {
+ s_gl_object object;
+ s_str path;
+ s_str real_path;
+ uw total_w;
+ uw total_h;
+ uw dim_x;
+ uw dim_y;
+ uw frame_count;
+ uw w;
+ uw h;
+ uw tex_w;
+ uw tex_h;
+ GLuint *texture;
+};
+
+/* 3 */
+
+struct gl_camera {
+ f32 aspect_ratio;
+ f32 clip_z_far;
+ f32 clip_z_near;
+ f32 fov_y;
+ s_vec3 position;
+ s_vec3 rotation;
+ s_vec3 scale;
+ s_mat4 projection_matrix;
+ s_mat4 view_matrix;
+ s_mat4 model_matrix;
+ GLint light_count;
+ s_vec3 light_pos[GL_CAMERA_LIGHT_MAX];
+ s_vec3 light_pos_cam[GL_CAMERA_LIGHT_MAX];
+ s_rgb light_color[GL_CAMERA_LIGHT_MAX];
+ GLuint gl_projection_matrix_loc;
+ GLuint gl_view_matrix_loc;
+ GLuint gl_model_matrix_loc;
+ GLuint gl_enable_tex2d_loc;
+ GLuint gl_tex2d_loc;
+ GLuint gl_light_pos_loc;
+ GLuint gl_light_color_loc;
+ GLuint gl_material_rough_loc;
+ GLuint gl_material_metal_loc;
+ GLuint gl_material_color_loc;
+ GLuint gl_shader_program;
+};
+
+struct gl_ortho {
+ f32 x1;
+ f32 x2;
+ f32 y1;
+ f32 y2;
+ f32 clip_z_near;
+ f32 clip_z_far;
+ s_vec3 position;
+ s_vec3 rotation;
+ s_vec3 scale;
+ s_mat4 projection_matrix;
+ GLuint gl_projection_matrix_loc;
+ s_mat4 view_matrix;
+ GLuint gl_view_matrix_loc;
+ s_mat4 model_matrix;
+ GLuint gl_model_matrix_loc;
+ GLuint gl_enable_tex2d_loc;
+ GLuint gl_tex2d_loc;
+ GLuint gl_color_loc;
+ GLuint gl_shader_program;
+ s_gl_square square;
+};
+
+#endif /* LIBKC3_WINDOW_SDL2_TYPES_H */
diff --git a/window/sdl2/update_sources b/window/sdl2/update_sources
new file mode 100755
index 0000000..7375817
--- /dev/null
+++ b/window/sdl2/update_sources
@@ -0,0 +1,30 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+. ../../config.subr
+
+echo "$PWD/update_sources"
+
+echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
+echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
+
+HEADERS="$(ls *.h | grep -v '^config.h$')"
+sources HEADERS "$HEADERS"
+
+SOURCES="$(ls *.c)"
+sources SOURCES "$SOURCES"
+
+update_sources_mk
+update_sources_sh
+
+( cd demo && ./update_sources; )
diff --git a/window/sdl2/vec2.c b/window/sdl2/vec2.c
new file mode 100644
index 0000000..75b4f46
--- /dev/null
+++ b/window/sdl2/vec2.c
@@ -0,0 +1,92 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "vec2.h"
+
+s_vec2 * vec2_init (s_vec2 *p, f32 x, f32 y)
+{
+ assert(p);
+ p->x = x;
+ p->y = y;
+ return p;
+}
+
+s_vec2 * vec2_init_copy (s_vec2 *p, const s_vec2 *src)
+{
+ assert(p);
+ assert(src);
+ p->x = src->x;
+ p->y = src->y;
+ return p;
+}
+
+s_vec2 *
+vec2_init_product (s_vec2 *p, const s_mat3 *m, const s_vec2 *s)
+{
+ assert(p);
+ assert(m);
+ assert(s);
+ p->x = s->x * m->xx + s->y * m->xy + m->xz;
+ p->y = s->x * m->yx + s->y * m->yy + m->yz;
+ return p;
+}
+
+s_vec2 * vec2_init_zero (s_vec2 *p)
+{
+ assert(p);
+ p->x = 0.0;
+ p->y = 0.0;
+ return p;
+}
+
+void vec2_delete (s_vec2 *p)
+{
+ free(p);
+}
+
+s_vec2 * vec2_new (f32 x, f32 y)
+{
+ s_vec2 *p;
+ p = calloc(1, sizeof(s_vec2));
+ if (! p) {
+ err_puts("vec2_new: failed to allocate memory");
+ return NULL;
+ }
+ vec2_init(p, x, y);
+ return p;
+}
+
+s_vec2 * vec2_new_copy (const s_vec2 *src)
+{
+ s_vec2 *p;
+ p = calloc(1, sizeof(s_vec2));
+ if (! p) {
+ err_puts("vec2_new: failed to allocate memory");
+ return NULL;
+ }
+ vec2_init_copy(p, src);
+ return p;
+}
+
+s_vec2 * vec2_new_zero (void)
+{
+ s_vec2 *p;
+ p = calloc(1, sizeof(s_vec2));
+ if (! p) {
+ err_puts("vec2_new: failed to allocate memory");
+ return NULL;
+ }
+ vec2_init_zero(p);
+ return p;
+}
diff --git a/window/sdl2/vec2.h b/window/sdl2/vec2.h
new file mode 100644
index 0000000..f975dc4
--- /dev/null
+++ b/window/sdl2/vec2.h
@@ -0,0 +1,32 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 VEC2_H
+#define VEC2_H
+
+#include "types.h"
+
+/* Stack-allocation compatible functions. */
+s_vec2 * vec2_init (s_vec2 *p, f32 x, f32 y);
+s_vec2 * vec2_init_copy (s_vec2 *p, const s_vec2 *src);
+s_vec2 * vec2_init_product (s_vec2 *p, const s_mat3 *m,
+ const s_vec2 *s);
+s_vec2 * vec2_init_zero (s_vec2 *p);
+
+/* Heap-allocation functions, call vec2_delete after use. */
+void vec2_delete (s_vec2 *p);
+s_vec2 * vec2_new (f32 x, f32 y);
+s_vec2 * vec2_new_copy (const s_vec2 *src);
+s_vec2 * vec2_new_product (const s_mat3 *m, const s_vec2 *s);
+s_vec2 * vec2_new_zero (void);
+
+#endif /* VEC2_H */
diff --git a/window/sdl2/vec3.c b/window/sdl2/vec3.c
new file mode 100644
index 0000000..1421a75
--- /dev/null
+++ b/window/sdl2/vec3.c
@@ -0,0 +1,127 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "vec3.h"
+
+s_vec3 * vec3_init (s_vec3 *p, f32 x, f32 y, f32 z)
+{
+ assert(p);
+ p->x = x;
+ p->y = y;
+ p->z = z;
+ return p;
+}
+
+s_vec3 * vec3_init_copy (s_vec3 *p, const s_vec3 *src)
+{
+ assert(p);
+ assert(src);
+ p->x = src->x;
+ p->y = src->y;
+ p->z = src->z;
+ return p;
+}
+
+s_vec3 * vec3_init_normalize (s_vec3 *p, const s_vec3 *src)
+{
+ f32 norm;
+ f32 ratio;
+ assert(p);
+ assert(src);
+ norm = vec3_norm(src);
+ ratio = 1.0f / norm;
+ p->x = src->x * ratio;
+ p->y = src->y * ratio;
+ p->z = src->z * ratio;
+ return p;
+}
+
+s_vec3 * mat4_mult_vec3 (const s_mat4 *a, const s_vec3 *b, s_vec3 *dest)
+{
+ assert(a);
+ assert(b);
+ assert(dest);
+ dest->x = a->xx * b->x + a->xy * b->y + a->xz * b->z + a->xt;
+ dest->y = a->yx * b->x + a->yy * b->y + a->yz * b->z + a->yt;
+ dest->z = a->zx * b->x + a->zy * b->y + a->zz * b->z + a->zt;
+ return dest;
+}
+
+s_vec3 * vec3_init_zero (s_vec3 *p)
+{
+ assert(p);
+ p->x = 0.0;
+ p->y = 0.0;
+ p->z = 0.0;
+ return p;
+}
+
+void vec3_delete (s_vec3 *p)
+{
+ free(p);
+}
+
+s_vec3 * vec3_new (f32 x, f32 y, f32 z)
+{
+ s_vec3 *p;
+ p = calloc(1, sizeof(s_vec3));
+ if (! p) {
+ err_puts("vec3_new: failed to allocate memory");
+ return NULL;
+ }
+ vec3_init(p, x, y, z);
+ return p;
+}
+
+s_vec3 * vec3_new_copy (const s_vec3 *src)
+{
+ s_vec3 *p;
+ p = calloc(1, sizeof(s_vec3));
+ if (! p) {
+ err_puts("vec3_new: failed to allocate memory");
+ return NULL;
+ }
+ vec3_init_copy(p, src);
+ return p;
+}
+
+s_vec3 * vec3_new_zero (void)
+{
+ s_vec3 *p;
+ p = calloc(1, sizeof(s_vec3));
+ if (! p) {
+ err_puts("vec3_new: failed to allocate memory");
+ return NULL;
+ }
+ vec3_init_zero(p);
+ return p;
+}
+
+f32 vec3_norm (const s_vec3 *p)
+{
+ assert(p);
+ return sqrtf(p->x * p->x + p->y * p->y + p->z * p->z);
+}
+
+void vec3_normalize (s_vec3 *p)
+{
+ f32 norm;
+ f32 ratio;
+ assert(p);
+ norm = vec3_norm(p);
+ ratio = 1.0f / norm;
+ p->x *= ratio;
+ p->y *= ratio;
+ p->z *= ratio;
+}
diff --git a/window/sdl2/vec3.h b/window/sdl2/vec3.h
new file mode 100644
index 0000000..0224588
--- /dev/null
+++ b/window/sdl2/vec3.h
@@ -0,0 +1,36 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 VEC3_H
+#define VEC3_H
+
+#include "types.h"
+
+/* Stack-allocation compatible functions. */
+s_vec3 * vec3_init (s_vec3 *p, f32 x, f32 y, f32 z);
+s_vec3 * vec3_init_copy (s_vec3 *p, const s_vec3 *src);
+s_vec3 * vec3_init_normalize (s_vec3 *p, const s_vec3 *src);
+s_vec3 * vec3_init_zero (s_vec3 *p);
+
+/* Heap-allocation functions, call vec3_delete after use. */
+void vec3_delete (s_vec3 *p);
+s_vec3 * vec3_new (f32 x, f32 y, f32 z);
+s_vec3 * vec3_new_copy (const s_vec3 *src);
+s_vec3 * vec3_new_zero (void);
+
+/* Operators. */
+void vec3_normalize (s_vec3 *p);
+
+/* Observers. */
+f32 vec3_norm (const s_vec3 *p);
+
+#endif /* VEC3_H */
diff --git a/window/sdl2/window_sdl2.c b/window/sdl2/window_sdl2.c
new file mode 100644
index 0000000..fa02a9b
--- /dev/null
+++ b/window/sdl2/window_sdl2.c
@@ -0,0 +1,316 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <err.h>
+#include <stdlib.h>
+#include <xkbcommon/xkbcommon.h>
+#include <libkc3/kc3.h>
+#include "../window.h"
+#include "gl_deprecated.h"
+#include "window_sdl2.h"
+
+const char *g_gray_3_bits_utf8[] = {
+ " ", ".", ":", "#", "░", "▒", "▓", "█"
+};
+
+static bool g_window_sdl2_initialized = false;
+
+static void gl_debug (GLenum source, GLenum type, GLuint id,
+ GLenum severity, GLsizei length,
+ const GLchar* message, const void* user_param)
+{
+ (void) source;
+ (void) type;
+ (void) id;
+ (void) severity;
+ (void) length;
+ (void) user_param;
+ err_write_1("gl_debug_callback: ");
+ err_puts(message);
+}
+
+void window_sdl2_clean (s_window_sdl2 *window)
+{
+ window_clean((s_window *) window);
+}
+
+bool window_sdl2_default_button_cb (s_window_sdl2 *window, u8 button,
+ sw x, sw y)
+{
+ assert(window);
+ (void) window;
+ (void) button;
+ (void) x;
+ (void) y;
+ printf("window_sdl2_default_button_cb: %d (%ld, %ld)\n",
+ (int) button, x, y);
+ return true;
+}
+
+bool window_sdl2_default_key_cb (s_window_sdl2 *window,
+ SDL_Keysym *keysym)
+{
+ assert(window);
+ assert(keysym);
+ (void) window;
+ (void) keysym;
+ printf("window_sdl2_default_key_cb: %d\n", keysym->sym);
+ return true;
+}
+
+bool window_sdl2_default_load_cb (s_window_sdl2 *window)
+{
+ assert(window);
+ (void) window;
+ printf("window_sdl2_default_load_cb\n");
+ return true;
+}
+
+bool window_sdl2_default_motion_cb (s_window_sdl2 *window, sw x, sw y)
+{
+ assert(window);
+ (void) window;
+ (void) x;
+ (void) y;
+ /*
+ printf("window_sdl2_default_motion_cb (%ld, %ld)\n", x, y);
+ */
+ return true;
+}
+
+bool window_sdl2_default_render_cb (s_window_sdl2 *window)
+{
+ assert(window);
+ (void) window;
+ printf("window_sdl2_default_render_cb\n");
+ return true;
+}
+
+bool window_sdl2_default_resize_cb (s_window_sdl2 *window, uw w, uw h)
+{
+ assert(window);
+ (void) window;
+ (void) w;
+ (void) h;
+ printf("window_sdl2_default_resize_cb: %lu x %lu\n", w, h);
+ return true;
+}
+
+void window_sdl2_default_unload_cb (s_window_sdl2 *window)
+{
+ assert(window);
+ (void) window;
+ printf("window_sdl2_default_unload_cb\n");
+}
+
+s_window_sdl2 * window_sdl2_init (s_window_sdl2 *window,
+ sw x, sw y, uw w, uw h,
+ const char *title,
+ uw sequence_count)
+{
+ s_window_sdl2 tmp = {0};
+ assert(window);
+ title = title ? title : "KC3.Window.Sdl2";
+ window_init((s_window *) &tmp, x, y, w, h, title, sequence_count);
+ tmp.button = window_sdl2_default_button_cb;
+ tmp.key = window_sdl2_default_key_cb;
+ tmp.load = window_sdl2_default_load_cb;
+ tmp.motion = window_sdl2_default_motion_cb;
+ tmp.render = window_sdl2_default_render_cb;
+ tmp.resize = window_sdl2_default_resize_cb;
+ tmp.unload = window_sdl2_default_unload_cb;
+ *window = tmp;
+ return window;
+}
+
+bool window_sdl2_run (s_window_sdl2 *window)
+{
+ SDL_GLContext context;
+ int mouse_x, mouse_y;
+ int quit = 0;
+ SDL_Event sdl_event;
+ SDL_Window *sdl_window;
+ assert(window);
+ if (! g_window_sdl2_initialized) {
+ //SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1");
+ if (SDL_Init(SDL_INIT_VIDEO)) {
+ warnx("window_sdl2_run: SDL initialization failed: %s",
+ SDL_GetError());
+ return false;
+ }
+ g_window_sdl2_initialized = true;
+ }
+ if (SDL_VideoInit(NULL)) {
+ warnx("window_sdl2_run: SDL_VideoInit failed: %s",
+ SDL_GetError());
+ return false;
+ }
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
+ SDL_GL_CONTEXT_PROFILE_CORE);
+ sdl_window = SDL_CreateWindow(window->title,
+ window->x, window->y,
+ window->w, window->h,
+ SDL_WINDOW_ALLOW_HIGHDPI |
+ SDL_WINDOW_OPENGL |
+ SDL_WINDOW_RESIZABLE |
+ SDL_WINDOW_SHOWN);
+ if (! sdl_window) {
+ warnx("window_sdl2_run: failed to create window: %s",
+ SDL_GetError());
+ return false;
+ }
+ SDL_SetWindowBordered(sdl_window, SDL_TRUE);
+ window->sdl_window = sdl_window;
+ context = SDL_GL_CreateContext(sdl_window);
+ if (! context) {
+ warnx("window_sdl2_run: failed to create OpenGL context: %s",
+ SDL_GetError());
+ return false;
+ }
+ GLenum gl_error = glGetError();
+ if (gl_error != GL_NO_ERROR) {
+ warnx("OpenGL initialization error: %s\n",
+ gl_error_string(gl_error));
+ goto ko;
+ }
+ glewExperimental = GL_TRUE;
+ if (glewInit() != GLEW_OK) {
+ warnx("window_sdl2_run: failed to initialize GLEW");
+ goto ko;
+ }
+ const char * version = (const char *) glGetString(GL_VERSION);
+ if (version) {
+ err_write_1("window_sdl2_run: OpenGL Version: ");
+ err_puts(version);
+ } else {
+ err_puts("window_sdl2_run: failed to retrieve OpenGL version");
+ goto ko;
+ }
+ if (glDebugMessageCallback) {
+ glEnable(GL_DEBUG_OUTPUT);
+ glDebugMessageCallback((GLDEBUGPROC) gl_debug, NULL);
+ }
+ if (SDL_GL_MakeCurrent(sdl_window, context) < 0) {
+ warnx("window_sdl2_run: failed to make OpenGL context current: %s",
+ SDL_GetError());
+ goto ko;
+ }
+ int gl_w = window->w;
+ int gl_h = window->h;
+ SDL_GL_GetDrawableSize(sdl_window, &gl_w, &gl_h);
+ window->gl_w = gl_w;
+ window->gl_h = gl_h;
+ int display_index;
+ display_index = SDL_GetWindowDisplayIndex(sdl_window);
+ if (display_index < 0) {
+ err_write_1("window_sdl2_run: failed to get display index: ");
+ err_puts(SDL_GetError());
+ goto ko;
+ }
+ if (SDL_GetDisplayDPI(display_index, &window->dpi, &window->dpi_w,
+ &window->dpi_h) != 0) {
+ err_write_1("window_sdl2_run: failed to get display DPI: ");
+ err_puts(SDL_GetError());
+ goto ko;
+ }
+ fprintf(stderr, "window_sdl2_run: dpi=%.2f, dpi_w=%.2f, dpi_h=%.2f\n",
+ window->dpi, window->dpi_w, window->dpi_h);
+ SDL_GL_SetSwapInterval(1);
+ assert(glGetError() == GL_NO_ERROR);
+ if (! window->load(window)) {
+ err_puts("window_sdl2_run: window->load => false");
+ goto ko;
+ }
+ assert(glGetError() == GL_NO_ERROR);
+ while (! quit) {
+ assert(glGetError() == GL_NO_ERROR);
+ while (SDL_PollEvent(&sdl_event) != 0) {
+ assert(glGetError() == GL_NO_ERROR);
+ switch (sdl_event.type) {
+ case SDL_QUIT:
+ err_puts("window_sdl2_run: SDL_QUIT");
+ quit = 1;
+ break;
+ case SDL_KEYDOWN:
+ if (! window->key(window, &sdl_event.key.keysym)) {
+ err_puts("window_sdl2_run: window->key => false");
+ quit = 1;
+ }
+ break;
+ case SDL_MOUSEBUTTONDOWN:
+ if (! window->button(window, sdl_event.button.button,
+ sdl_event.button.x, sdl_event.button.y)) {
+ err_puts("window_sdl2_run: window->button => false");
+ quit = 1;
+ }
+ break;
+ case SDL_MOUSEWHEEL:
+ SDL_GetMouseState(&mouse_x, &mouse_y);
+ if (! window->button(window, sdl_event.wheel.y > 0 ? 4 : 5,
+ mouse_x, mouse_y)) {
+ err_puts("window_sdl2_run: window->button => false");
+ quit = 1;
+ }
+ break;
+ case SDL_MOUSEMOTION:
+ //int relativeX = sdl_event.motion.xrel;
+ //int relativeY = sdl_event.motion.yrel;
+ if (! window->motion(window, sdl_event.motion.x,
+ sdl_event.motion.y)) {
+ err_puts("window_sdl2_run: window->motion => false");
+ quit = 1;
+ }
+ break;
+ case SDL_WINDOWEVENT:
+ if (sdl_event.window.event == SDL_WINDOWEVENT_RESIZED) {
+ if (! window->resize(window, sdl_event.window.data1,
+ sdl_event.window.data2)) {
+ err_puts("window_sdl2_run: window->resize => false");
+ quit = 1;
+ }
+ assert(glGetError() == GL_NO_ERROR);
+ window->w = sdl_event.window.data1;
+ window->h = sdl_event.window.data2;
+ SDL_GL_GetDrawableSize(sdl_window, &gl_w, &gl_h);
+ assert(glGetError() == GL_NO_ERROR);
+ window->gl_w = gl_w;
+ window->gl_h = gl_h;
+ glViewport(0, 0, gl_w, gl_h);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ assert(glGetError() == GL_NO_ERROR);
+ //glDrawBuffer(GL_BACK);
+ if (! window->render(window)) {
+ err_puts("window_sdl2_run: window->render => false");
+ quit = 1;
+ }
+ SDL_GL_SwapWindow(sdl_window);
+ }
+ SDL_GL_DeleteContext(context);
+ SDL_DestroyWindow(sdl_window);
+ return true;
+ ko:
+ SDL_GL_DeleteContext(context);
+ SDL_DestroyWindow(sdl_window);
+ return false;
+}
diff --git a/window/sdl2/window_sdl2.h b/window/sdl2/window_sdl2.h
new file mode 100644
index 0000000..ed80fc1
--- /dev/null
+++ b/window/sdl2/window_sdl2.h
@@ -0,0 +1,42 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_SDL2_H
+#define LIBKC3_WINDOW_SDL2_H
+
+#include "types.h"
+
+extern const char *g_gray_3_bits_utf8[];
+
+/* Stack-allocation compatible functions, call window_sdl2_clean
+ after use. */
+void window_sdl2_clean (s_window_sdl2 *window);
+s_window_sdl2 * window_sdl2_init (s_window_sdl2 *window,
+ sw x, sw y, uw w, uw h,
+ const char *title,
+ uw sequence_count);
+
+/* Operators. */
+bool window_sdl2_run (s_window_sdl2 *window);
+
+/* Callbacks. */
+bool window_sdl2_default_button_cb (s_window_sdl2 *window, u8 button,
+ sw x, sw y);
+bool window_sdl2_default_key_cb (s_window_sdl2 *window,
+ SDL_Keysym *keysym);
+bool window_sdl2_default_load_cb (s_window_sdl2 *window);
+bool window_sdl2_default_motion_cb (s_window_sdl2 *window, sw x, sw y);
+bool window_sdl2_default_render_cb (s_window_sdl2 *window);
+bool window_sdl2_default_resize_cb (s_window_sdl2 *window, uw w, uw h);
+void window_sdl2_default_unload_cb (s_window_sdl2 *window);
+
+#endif /* LIBKC3_WINDOW_SDL2_H */
diff --git a/window/sources.mk b/window/sources.mk
new file mode 100644
index 0000000..990366e
--- /dev/null
+++ b/window/sources.mk
@@ -0,0 +1,8 @@
+# sources.mk generated by update_sources
+HEADERS = \
+ "types.h" \
+ "window.h" \
+
+SOURCES = \
+ "window.c" \
+
diff --git a/window/sources.sh b/window/sources.sh
new file mode 100644
index 0000000..8a6bfbb
--- /dev/null
+++ b/window/sources.sh
@@ -0,0 +1,3 @@
+# sources.sh generated by update_sources
+HEADERS='types.h window.h '
+SOURCES='window.c '
diff --git a/window/types.h b/window/types.h
new file mode 100644
index 0000000..b2e7e59
--- /dev/null
+++ b/window/types.h
@@ -0,0 +1,72 @@
+/* kc3
+ * Copyright 2022,2023,2024 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.
+ */
+/** @file types.h
+ * @brief Module C3.Window
+ *
+ * Base struct for all GUI window operations.
+ */
+#ifndef LIBKC3_WINDOW_TYPES_H
+#define LIBKC3_WINDOW_TYPES_H
+
+#include <libkc3/types.h>
+
+typedef struct window s_window;
+
+/* return false to break event loop */
+typedef bool (*f_window_button) (s_window *window, u8 button,
+ uw x, uw y);
+
+/* return false to break event loop */
+typedef bool (*f_window_key) (s_window *window, uw sym);
+
+/* return false to break event loop */
+typedef bool (*f_window_load) (s_window *window);
+
+/* return false to break event loop */
+typedef bool (*f_window_motion) (s_window *window, sw x, sw y);
+
+/* return false to break event loop */
+typedef bool (*f_window_render) (s_window *window);
+
+/* return false to break event loop */
+typedef bool (*f_window_resize) (s_window *window,
+ uw w, uw h);
+
+typedef void (*f_window_unload) (s_window *window);
+
+/* To subtype make a copy of this struct while replacing
+ * pointer types (including pointer to function types).
+ * E.g. see libkc3/window/cairo/types.h */
+struct window {
+ sw x;
+ sw y;
+ uw w;
+ uw h;
+ bool fullscreen;
+ f_window_button button;
+ f_window_key key;
+ f_window_load load;
+ f_window_motion motion;
+ f_window_render render;
+ void *context;
+ f_window_resize resize;
+ s_sequence *seq;
+ s_sequence *sequence;
+ uw sequence_count;
+ uw sequence_pos;
+ s_tag tag; // TODO: move sequence to tag
+ const char *title;
+ f_window_unload unload;
+};
+
+#endif /* LIBKC3_WINDOW_TYPES_H */
diff --git a/window/update_sources b/window/update_sources
new file mode 100755
index 0000000..c7c9b07
--- /dev/null
+++ b/window/update_sources
@@ -0,0 +1,31 @@
+#!/bin/sh
+## kc3
+## Copyright 2022-2024 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.
+
+. ../config.subr
+
+echo "$PWD/update_sources"
+
+echo "# sources.mk generated by update_sources" > ${SOURCES_MK}
+echo "# sources.sh generated by update_sources" > ${SOURCES_SH}
+
+HEADERS="$(ls *.h | grep -v '^config.h$')"
+sources HEADERS "$HEADERS"
+
+SOURCES="$(ls *.c)"
+sources SOURCES "$SOURCES"
+
+update_sources_mk
+update_sources_sh
+
+( cd cairo && ./update_sources; )
+( cd sdl2 && ./update_sources; )
diff --git a/window/window.c b/window/window.c
new file mode 100644
index 0000000..19f60e8
--- /dev/null
+++ b/window/window.c
@@ -0,0 +1,105 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 <libkc3/kc3.h>
+#include "window.h"
+
+bool window_animate (s_window *window)
+{
+ s_timespec clock_monotonic;
+ s_timespec delta;
+ s_sequence *seq;
+ f64 t;
+ if (clock_gettime(CLOCK_MONOTONIC, &clock_monotonic)) {
+ err_puts("window_animate: clock_gettime");
+ return false;
+ }
+ if (window->sequence_pos >= window->sequence_count) {
+ err_puts("window_animate: window->sequence_pos >="
+ " window->sequence_count");
+ return false;
+ }
+ seq = window->sequence + window->sequence_pos;
+ time_sub(&clock_monotonic, &seq->t0, &delta);
+ time_to_f64(&delta, &t);
+ seq->dt = t - seq->t;
+ seq->frame++;
+ seq->t = t;
+ /* printf("window_animate: %f\n", t); */
+ if (t > seq->duration &&
+ ! window_set_sequence_pos(window, (window->sequence_pos + 1) %
+ window->sequence_count))
+ return false;
+ return true;
+}
+
+void window_clean (s_window *window)
+{
+ uw i;
+ assert(window);
+ i = 0;
+ if (window->seq && window->seq->unload)
+ window->seq->unload(window->seq);
+ while (i < window->sequence_count) {
+ sequence_clean(window->sequence + i);
+ i++;
+ }
+ free(window->sequence);
+ tag_clean(&window->tag);
+ window->unload(window);
+}
+
+s_window * window_init (s_window *window,
+ sw x, sw y, uw w, uw h,
+ const char *title,
+ uw sequence_count)
+{
+ s_window tmp = {0};
+ assert(window);
+ tmp.x = x;
+ tmp.y = y;
+ tmp.w = w;
+ tmp.h = h;
+ tmp.sequence = calloc(sequence_count, sizeof(s_sequence));
+ tmp.sequence_count = sequence_count;
+ tmp.sequence_pos = 0;
+ tag_init_void(&tmp.tag);
+ tmp.title = title ? title : "KC3.Window";
+ *window = tmp;
+ return window;
+}
+
+bool window_set_sequence_pos (s_window *window, uw sequence_pos)
+{
+ s_sequence *seq;
+ assert(window);
+ printf("window_set_sequence_pos %lu\n", sequence_pos);
+ if (sequence_pos >= window->sequence_count)
+ return false;
+ seq = window->sequence + sequence_pos;
+ seq->dt = 0.0;
+ seq->frame = 0;
+ seq->t = 0.0;
+ if (clock_gettime(CLOCK_MONOTONIC, &seq->t0)) {
+ err_puts("window_set_sequence_pos: clock_gettime");
+ return false;
+ }
+ window->sequence_pos = sequence_pos;
+ if (window->seq)
+ if (! window->seq->unload(window->seq))
+ return false;
+ window->seq = seq;
+ io_puts(seq->title);
+ if (! seq->load(seq))
+ return false;
+ return true;
+}
diff --git a/window/window.h b/window/window.h
new file mode 100644
index 0000000..0e0a796
--- /dev/null
+++ b/window/window.h
@@ -0,0 +1,31 @@
+/* kc3
+ * Copyright 2022,2023,2024 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 LIBKC3_WINDOW_H
+#define LIBKC3_WINDOW_H
+
+#include <libkc3/types.h>
+#include "types.h"
+
+/* Stack-allocation compatible functions, call window_clean
+ after use. */
+void window_clean (s_window *window);
+s_window * window_init (s_window *window,
+ sw x, sw y, uw w, uw h,
+ const char *title,
+ uw sequence_count);
+
+/* Operators. */
+bool window_animate (s_window *window);
+bool window_set_sequence_pos (s_window *window, uw sequence_pos);
+
+#endif /* LIBKC3_WINDOW_H */