diff --git a/.gitmodules b/.gitmodules
index 504d36c..9e0001c 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -13,6 +13,3 @@
[submodule "fonts"]
path = fonts
url = https://git.kmx.io/c3-lang/fonts.git
-[submodule "ftgl"]
- path = ftgl
- url = https://git.kmx.io/c3-lang/ftgl.git
diff --git a/config.subr b/config.subr
index 995dcd9..f877fec 100644
--- a/config.subr
+++ b/config.subr
@@ -218,9 +218,48 @@ config_objc_lib_have() {
rm -f "$OUT" "$OUT_M"
}
+cpp_o_rule() {
+ "$CXX" $CPPFLAGS $CXXFLAGS -M "$1" || { echo "$1" | sed -e 's/^\(.*\)\.cpp$/\1.o: \1.cpp/'; }
+ echo "$1" | sed -e 's/^\(.*\)\.cpp$/\1.o: Makefile config.mk/'
+}
+
+cpp_ext_rule() {
+ cpp_o_rule "$2" | sed -e "s/[.]o:/$1:/"
+}
+
+cpp_lo_rule() {
+ cpp_ext_rule .lo "$1"
+}
+
+cpp_prog_rule() {
+ { cpp_o_rule "$1" || exit 1; } | sed -e 's/[.]o:/:/'
+}
+
+cpp2ext() {
+ EXT="$1"; shift
+ echo "$@" | sed -e "s/[.]cpp$/${EXT}/" -e "s/[.]cpp /${EXT} /g"
+}
+
+cpp2la() {
+ cpp2ext .la "$@"
+}
+
+cpp2lo() {
+ cpp2ext .lo "$@"
+}
+
+cpp2o() {
+ cpp2ext .o "$@"
+}
+
+cpp2prog() {
+ echo "$@" | sed -e 's/[.]cpp$//' -e 's/[.]cpp / /g'
+}
+
env_reset() {
CPPFLAGS="$ENV_CPPFLAGS"
CFLAGS="$ENV_CFLAGS"
+ CXXFLAGS="$ENV_CXXFLAGS"
LDFLAGS="$ENV_LDFLAGS"
LIBS="$ENV_LIBS"
}
@@ -242,6 +281,7 @@ objc2ext() {
pkg_config() {
if pkg-config "$1"; then
CFLAGS="$CFLAGS $(pkg-config --cflags "$1")"
+ CXXFLAGS="$CXXFLAGS $(pkg-config --cflags "$1")"
LIBS="$LIBS $(pkg-config --libs "$1")"
fi
}
@@ -254,10 +294,11 @@ require_pkg_config() {
}
sources() {
+ SOURCES_TMP="$(echo "$2" | sort -u)"
echo "$1 = \\
-$(echo "$2" | sed -e 's/^\(.*\)$/ "\1" \\/')
+$(echo "$SOURCES_TMP" | sed -e 's/^\(.*\)$/ "\1" \\/')
" >> ${SOURCES_MK}
- echo "$1='$(echo "$2" | tr '\n' ' ')'" >> ${SOURCES_SH}
+ echo "$1='$(echo "$SOURCES_TMP" | tr '\n' ' ')'" >> ${SOURCES_SH}
}
swift_o_rule() {
@@ -332,6 +373,7 @@ echo "SRC_TOP = $SRC_TOP" >> ${CONFIG_MK}
ENV_CPPFLAGS="$CPPFLAGS"
ENV_CFLAGS="$CFLAGS"
+ENV_CXXFLAGS="$CXXFLAGS"
ENV_LDFLAGS="$LDFLAGS"
ENV_LIBS="$LIBS"
@@ -347,6 +389,15 @@ echo "CC = $CC" >> ${CONFIG_MK}
CC_TARGET=$(LC_ALL=C cc -v 2>&1 | grep 'Target: ' | cut -c 9-)
echo "CC_TARGET = $CC_TARGET" >> ${CONFIG_MK}
+if [ "x$CXX" = "x" ]; then
+ if test -n $(which c++); then
+ CXX=c++
+ elif test -n $(which g++); then
+ CXX=g++
+ fi
+fi
+echo "CXX = $CXX" >> ${CONFIG_MK}
+
if [ "x$GCOV" = "xfalse" ]; then
HAVE_GCOV=false
else
diff --git a/ftgl b/ftgl
deleted file mode 160000
index ddc7716..0000000
--- a/ftgl
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit ddc77166651a71ae037ef3129a285440aa559b2d
diff --git a/libc3/Makefile b/libc3/Makefile
index 57fb5d8..3c93399 100644
--- a/libc3/Makefile
+++ b/libc3/Makefile
@@ -24,9 +24,9 @@ build:
all:
${MAKE} build
- if ${HAVE_GCOV}; then ${MAKE} cov; fi
${MAKE} debug
if ${HAVE_ASAN}; then ${MAKE} asan; fi
+ if ${HAVE_GCOV}; then ${MAKE} cov; fi
${MAKE} -C window all
asan:
diff --git a/libc3/buf.h b/libc3/buf.h
index eb5e8e3..f6ad5bd 100644
--- a/libc3/buf.h
+++ b/libc3/buf.h
@@ -58,6 +58,7 @@ sw buf_peek_s16 (s_buf *buf, s16 *p);
sw buf_peek_s32 (s_buf *buf, s32 *p);
sw buf_peek_s64 (s_buf *buf, s64 *p);
sw buf_peek_str (s_buf *buf, const s_str *src);
+sw buf_peek_to_str (s_buf *buf, s_str *dest);
sw buf_peek_u8 (s_buf *buf, u8 *p);
sw buf_peek_u16 (s_buf *buf, u16 *p);
sw buf_peek_u32 (s_buf *buf, u32 *p);
diff --git a/libc3/io.c b/libc3/io.c
index a811045..059ce3e 100644
--- a/libc3/io.c
+++ b/libc3/io.c
@@ -106,6 +106,7 @@ sw io_write_1 (const s8 *x)
DEF_ERR_IO_INSPECT(array, const s_array *)
DEF_ERR_IO_INSPECT(call, const s_call *)
+DEF_ERR_IO_INSPECT(character, const character *)
DEF_ERR_IO_INSPECT(fact, const s_fact *)
DEF_ERR_IO_INSPECT(fn_pattern, const s_list *)
DEF_ERR_IO_INSPECT(list, const s_list **)
diff --git a/libc3/window/Makefile b/libc3/window/Makefile
index 14505c2..a85c1b4 100644
--- a/libc3/window/Makefile
+++ b/libc3/window/Makefile
@@ -17,9 +17,9 @@ build:
all:
${MAKE} build
- if ${HAVE_GCOV}; then ${MAKE} cov; fi
${MAKE} debug
if ${HAVE_ASAN}; then ${MAKE} asan; fi
+ if ${HAVE_GCOV}; then ${MAKE} cov; fi
asan:
${MAKE} ${LIB_ASAN}
diff --git a/libc3/window/sdl2/Makefile b/libc3/window/sdl2/Makefile
index 0d50f25..4e66db5 100644
--- a/libc3/window/sdl2/Makefile
+++ b/libc3/window/sdl2/Makefile
@@ -16,6 +16,9 @@ build:
all:
${MAKE} build
+ ${MAKE} debug
+ if ${HAVE_ASAN}; then ${MAKE} asan; fi
+ if ${HAVE_GCOV}; then ${MAKE} cov; fi
asan:
${MAKE} ${LIB_ASAN}
diff --git a/libc3/window/sdl2/configure b/libc3/window/sdl2/configure
index 6c9b166..8cc878c 100755
--- a/libc3/window/sdl2/configure
+++ b/libc3/window/sdl2/configure
@@ -37,13 +37,14 @@ OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
# Common config for all targets
CPPFLAGS="-I../../../libffi/include -I../../.. $CPPFLAGS"
+CPPFLAGS="-Iftgl/src $CPPFLAGS"
#CPPFLAGS="$CPPFLAGS -DGL_SILENCE_DEPRECATION=1"
CFLAGS="$CFLAGS -W -Wall -Werror -std=c99 -pedantic"
LDFLAGS="--shared ${LDFLAGS}"
LIBS="$LIBS -rpath ${PREFIX}/lib"
config_asan
config_gnu
-pkg_config ftgl
+pkg_config freetype2
pkg_config gl
pkg_config glew
pkg_config glu
diff --git a/libc3/window/sdl2/demo/configure b/libc3/window/sdl2/demo/configure
index 1c0d618..983d9a5 100755
--- a/libc3/window/sdl2/demo/configure
+++ b/libc3/window/sdl2/demo/configure
@@ -51,7 +51,7 @@ LIBS="$LIBS -lm"
config_asan
config_gnu
pkg_config libbsd-overlay
-pkg_config ftgl
+pkg_config freetype2
pkg_config gl
pkg_config glu
pkg_config glut
diff --git a/libc3/window/sdl2/demo/earth.c b/libc3/window/sdl2/demo/earth.c
index ec0c40a..c080b9a 100644
--- a/libc3/window/sdl2/demo/earth.c
+++ b/libc3/window/sdl2/demo/earth.c
@@ -13,7 +13,6 @@
#include <math.h>
#include <libc3/c3.h>
#include "../window_sdl2.h"
-#include "../sdl2_font.h"
#include "../sdl2_sprite.h"
#include "../gl_camera.h"
#include "../gl_sphere.h"
@@ -64,14 +63,14 @@ bool earth_render (s_sequence *seq, s_window_sdl2 *window,
(void) context;
if (! seq || seq->tag.type != TAG_MAP ||
seq->tag.data.map.count != 3) {
- warnx("earth_render: invalid seq->tag");
+ 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) {
- warnx("earth_render: invalid map");
+ err_puts("earth_render: invalid map");
return false;
}
camera = map->value[0].data.ptr_free.p;
diff --git a/libc3/window/sdl2/demo/flies.c b/libc3/window/sdl2/demo/flies.c
index 758871e..7469afb 100644
--- a/libc3/window/sdl2/demo/flies.c
+++ b/libc3/window/sdl2/demo/flies.c
@@ -12,9 +12,10 @@
*/
#include <math.h>
#include <libc3/c3.h>
-#include "../window_sdl2.h"
-#include "../sdl2_font.h"
+#include "../gl_font.h"
+#include "../gl_text.h"
#include "../sdl2_sprite.h"
+#include "../window_sdl2.h"
#include "flies.h"
#define BOARD_SIZE 25
@@ -31,9 +32,11 @@ static const u8 g_board_item_space = BOARD_ITEM_SPACE;
static const u8 g_board_item_block = BOARD_ITEM_BLOCK;
static const u8 g_board_item_fly = BOARD_ITEM_FLY;
static const u8 g_board_item_dead_fly = BOARD_ITEM_DEAD_FLY;
-s_sdl2_font g_font_flies = {0};
+s_gl_font g_font_flies = {0};
s_sdl2_sprite g_sprite_dead_fly = {0};
s_sdl2_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)
@@ -196,9 +199,10 @@ bool flies_render (s_sequence *seq, s_window_sdl2 *window,
buf_write_1(&buf, "In ");
buf_inspect_uw(&buf, fly_in);
buf_write_u8(&buf, 0);
- sdl2_font_set_size(&g_font_flies, board_item_h,
- window->dpi);
- sdl2_font_render_text(&g_font_flies, buf.ptr.ps8);
+ gl_font_set_size(&g_font_flies, board_item_h,
+ (f64) window->gl_h / window->h);
+ gl_text_update_1(&g_text_flies_in, a);
+ gl_text_render(&g_text_flies_in);
buf_init(&buf, false, sizeof(a), a);
buf_write_1(&buf, "Out ");
buf_inspect_uw(&buf, fly_out);
@@ -206,7 +210,8 @@ bool flies_render (s_sequence *seq, s_window_sdl2 *window,
x = board_item_w * (BOARD_SIZE / 2 + 1);
glPushMatrix(); {
glTranslated(x, 0.0, 0.0);
- sdl2_font_render_text(&g_font_flies, buf.ptr.ps8);
+ gl_text_update_1(&g_text_flies_out, a);
+ gl_text_render(&g_text_flies_out);
} glPopMatrix();
glTranslated(0.0, board_item_h, 0.0);
glColor4f(0.6f, 0.7f, 0.9f, 1.0f);
diff --git a/libc3/window/sdl2/demo/flies.h b/libc3/window/sdl2/demo/flies.h
index c8feb15..9b3adc3 100644
--- a/libc3/window/sdl2/demo/flies.h
+++ b/libc3/window/sdl2/demo/flies.h
@@ -16,7 +16,7 @@
#include "../types.h"
#include "window_sdl2_demo.h"
-extern s_sdl2_font g_font_flies;
+extern s_gl_font g_font_flies;
extern s_sdl2_sprite g_sprite_dead_fly;
extern s_sdl2_sprite g_sprite_fly;
diff --git a/libc3/window/sdl2/demo/window_sdl2_demo.c b/libc3/window/sdl2/demo/window_sdl2_demo.c
index 75cd2f4..43249d1 100644
--- a/libc3/window/sdl2/demo/window_sdl2_demo.c
+++ b/libc3/window/sdl2/demo/window_sdl2_demo.c
@@ -14,9 +14,10 @@
#include <stdlib.h>
#include <libc3/c3.h>
#include "../../window.h"
+#include "../gl_font.h"
#include "../gl_matrix_4d.h"
#include "../gl_ortho.h"
-#include "../sdl2_font.h"
+#include "../gl_text.h"
#include "../sdl2_sprite.h"
#include "../window_sdl2.h"
#include "bg_rect.h"
@@ -27,9 +28,11 @@
#define WINDOW_SDL2_DEMO_SEQUENCE_COUNT 5
-//s_sdl2_font g_font_computer_modern;
-s_sdl2_font g_font_courier_new = {0};
-s_gl_ortho g_ortho = {0};
+//s_gl_font g_font_computer_modern = {0};
+s_gl_font g_font_courier_new = {0};
+s_gl_ortho g_ortho = {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);
@@ -45,6 +48,10 @@ 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 (! c3_init(NULL, argc, argv)) {
err_puts("c3_init");
return 1;
@@ -68,6 +75,7 @@ int main (int argc, char **argv)
window_sdl2_clean(&window);
c3_clean(NULL);
SDL_Quit();
+ FT_Done_FreeType(g_ft);
return 0;
}
@@ -90,15 +98,17 @@ bool window_sdl2_demo_key (s_window_sdl2 *window, SDL_Keysym *keysym)
if (! window->fullscreen) {
if (SDL_SetWindowFullscreen(window->sdl_window,
SDL_WINDOW_FULLSCREEN_DESKTOP)) {
- warnx("window_sdl2_demo_key: SDL_SetWindowFullscreen(:desktop): %s",
- SDL_GetError());
+ 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)) {
- warnx("window_sdl2_demo_key: SDL_SetWindowFullscreen(0): %s",
- SDL_GetError());
+ err_write_1("window_sdl2_demo_key:"
+ " SDL_SetWindowFullscreen(0): ");
+ err_puts(SDL_GetError());
SDL_RestoreWindow(window->sdl_window);
}
}
@@ -139,9 +149,13 @@ bool window_sdl2_demo_load (s_window_sdl2 *window)
}
if (! gl_ortho_init(&g_ortho))
return false;
- if (! sdl2_font_init(&g_font_courier_new,
+ if (! gl_font_init(&g_font_courier_new,
"fonts/Courier New/Courier New.ttf"))
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;
window_sdl2_sequence_init(window->sequence, 8.0,
"01. Background rectangles",
bg_rect_load, bg_rect_render);
@@ -157,7 +171,7 @@ bool window_sdl2_demo_load (s_window_sdl2 *window)
window_sdl2_sequence_init(window->sequence + 2, 60.0,
"03. Toasters",
toasters_load, toasters_render);
- if (! sdl2_font_init(&g_font_flies,
+ if (! gl_font_init(&g_font_flies,
"fonts/Courier New/Courier New.ttf"))
return false;
if (! sdl2_sprite_init(&g_sprite_fly, "img/fly-noto.png",
@@ -185,8 +199,7 @@ bool window_sdl2_demo_load (s_window_sdl2 *window)
return true;
}
-static void render_text (s_sdl2_font *font, f64 x, f64 y,
- const s8 *p)
+static void render_text (s_gl_text *text, f64 x, f64 y)
{
assert(glGetError() == GL_NO_ERROR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
@@ -197,43 +210,43 @@ static void render_text (s_sdl2_font *font, f64 x, f64 y,
gl_ortho_update_model_matrix(&g_ortho);
glBlendColor(1.0f, 1.0f, 1.0f, 1.0f);
assert(glGetError() == GL_NO_ERROR);
- sdl2_font_render_text(font, p);
+ gl_text_render(text);
assert(glGetError() == GL_NO_ERROR);
gl_matrix_4d_translate(&g_ortho.model_matrix, 1.0, 0.0, 0.0);
gl_ortho_update_model_matrix(&g_ortho);
assert(glGetError() == GL_NO_ERROR);
- sdl2_font_render_text(font, p);
+ gl_text_render(text);
gl_matrix_4d_translate(&g_ortho.model_matrix, 1.0, 0.0, 0.0);
gl_ortho_update_model_matrix(&g_ortho);
- sdl2_font_render_text(font, p);
+ gl_text_render(text);
gl_matrix_4d_translate(&g_ortho.model_matrix, 1.0, 0.0, 0.0);
gl_ortho_update_model_matrix(&g_ortho);
glTranslatef( 0.0f, 1.0f, 0.0f);
- sdl2_font_render_text(font, p);
+ gl_text_render(text);
gl_matrix_4d_translate(&g_ortho.model_matrix, 1.0, 0.0, 0.0);
gl_ortho_update_model_matrix(&g_ortho);
glTranslatef(-1.0f, 0.0f, 0.0f);
- sdl2_font_render_text(font, p);
+ gl_text_render(text);
gl_matrix_4d_translate(&g_ortho.model_matrix, 1.0, 0.0, 0.0);
gl_ortho_update_model_matrix(&g_ortho);
glTranslatef(-1.0f, 0.0f, 0.0f);
- sdl2_font_render_text(font, p);
+ gl_text_render(text);
gl_matrix_4d_translate(&g_ortho.model_matrix, 1.0, 0.0, 0.0);
gl_ortho_update_model_matrix(&g_ortho);
glTranslatef( 0.0f, 1.0f, 0.0f);
- sdl2_font_render_text(font, p);
+ gl_text_render(text);
gl_matrix_4d_translate(&g_ortho.model_matrix, 1.0, 0.0, 0.0);
gl_ortho_update_model_matrix(&g_ortho);
glTranslatef( 1.0f, 0.0f, 0.0f);
- sdl2_font_render_text(font, p);
+ gl_text_render(text);
gl_matrix_4d_translate(&g_ortho.model_matrix, 1.0, 0.0, 0.0);
gl_ortho_update_model_matrix(&g_ortho);
glTranslatef( 1.0f, 0.0f, 0.0f);
- sdl2_font_render_text(font, p);
- glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
+ gl_text_render(text);
+ glBlendColor(0.0f, 0.0f, 0.0f, 1.0f);
gl_matrix_4d_translate(&g_ortho.model_matrix, -1.0, -1.0, 0.0);
gl_ortho_update_model_matrix(&g_ortho);
- sdl2_font_render_text(font, p);
+ gl_text_render(text);
assert(glGetError() == GL_NO_ERROR);
}
@@ -246,28 +259,38 @@ bool window_sdl2_demo_render (s_window_sdl2 *window, void *context)
return false;
seq = window->sequence + window->sequence_pos;
gl_ortho_render(&g_ortho);
+ glEnable(GL_BLEND);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
+ GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
if (! seq->render(seq, window, context))
return false;
/* 2D */
glDisable(GL_DEPTH_TEST);
assert(glGetError() == GL_NO_ERROR);
- sdl2_font_set_size(&g_font_courier_new, 20, window->dpi);
- render_text(&g_font_courier_new, 20.0f, 30.0f, seq->title);
+ gl_font_set_size(&g_font_courier_new, 20,
+ (f64) window->gl_h / window->h);
+ gl_text_update_1(&g_text_seq_title, seq->title);
+ render_text(&g_text_seq_title, 20.0f, 30.0f);
/* progress bar */
- glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
- glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+ assert(glGetError() == GL_NO_ERROR);
+ glBlendColor(1.0f, 1.0f, 1.0f, 1.0f);
+ assert(glGetError() == GL_NO_ERROR);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ assert(glGetError() == GL_NO_ERROR);
glRectd(19, 11,
19 + (window->w - 40.0) * seq->t / seq->duration + 2,
11 + 4);
- glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
+ glBlendColor(0.0f, 0.0f, 0.0f, 1.0f);
glRectd(20, 12,
20 + (window->w - 40.0) * seq->t / seq->duration,
12 + 2);
assert(glGetError() == GL_NO_ERROR);
/* fps */
s8 fps[32];
- snprintf(fps, sizeof(fps), "%.2f", (f64) seq->frame / seq->t);
- render_text(&g_font_courier_new, 20, window->h - 30, fps);
+ snprintf(fps, sizeof(fps), "%.1f", (f64) seq->frame / seq->t);
+ gl_text_update_1(&g_text_fps, fps);
+ render_text(&g_text_fps, 20, window->h - 30);
gl_ortho_render_end(&g_ortho);
return true;
}
@@ -288,10 +311,10 @@ void window_sdl2_demo_unload (s_window_sdl2 *window)
assert(window);
(void) window;
gl_ortho_clean(&g_ortho);
- sdl2_font_clean(&g_font_courier_new);
+ gl_font_clean(&g_font_courier_new);
sdl2_sprite_clean(&g_sprite_toaster);
sdl2_sprite_clean(&g_sprite_toast);
- sdl2_font_clean(&g_font_flies);
+ gl_font_clean(&g_font_flies);
sdl2_sprite_clean(&g_sprite_fly);
sdl2_sprite_clean(&g_sprite_dead_fly);
sdl2_sprite_clean(&g_sprite_earth);
diff --git a/libc3/window/sdl2/demo/window_sdl2_demo.h b/libc3/window/sdl2/demo/window_sdl2_demo.h
index 57e8e45..371e1a9 100644
--- a/libc3/window/sdl2/demo/window_sdl2_demo.h
+++ b/libc3/window/sdl2/demo/window_sdl2_demo.h
@@ -15,7 +15,7 @@
#include "../types.h"
-extern s_sdl2_font g_font_computer_modern;
-extern s_sdl2_font g_font_courier_new;
+extern s_gl_font g_font_computer_modern;
+extern s_gl_font g_font_courier_new;
#endif /* LIBC3_WINDOW_SDL2_DEMO_H */
diff --git a/libc3/window/sdl2/disabled/sdl2_font.c b/libc3/window/sdl2/disabled/sdl2_font.c
new file mode 100644
index 0000000..c5d8423
--- /dev/null
+++ b/libc3/window/sdl2/disabled/sdl2_font.c
@@ -0,0 +1,65 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#include <libc3/c3.h>
+#include "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/libc3/window/sdl2/disabled/sdl2_font.h b/libc3/window/sdl2/disabled/sdl2_font.h
new file mode 100644
index 0000000..223196d
--- /dev/null
+++ b/libc3/window/sdl2/disabled/sdl2_font.h
@@ -0,0 +1,29 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#ifndef LIBC3_WINDOW_SDL2_SDL2_FONT_H
+#define LIBC3_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 /* LIBC3_WINDOW_SDL2_SDL2_FONT_H */
diff --git a/libc3/window/sdl2/gl_cylinder.c b/libc3/window/sdl2/gl_cylinder.c
index 152d59c..42db6af 100644
--- a/libc3/window/sdl2/gl_cylinder.c
+++ b/libc3/window/sdl2/gl_cylinder.c
@@ -15,6 +15,12 @@
#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)
{
diff --git a/libc3/window/sdl2/gl_font.c b/libc3/window/sdl2/gl_font.c
new file mode 100644
index 0000000..1a1f9b9
--- /dev/null
+++ b/libc3/window/sdl2/gl_font.c
@@ -0,0 +1,54 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#include <libc3/c3.h>
+#include "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 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("gl_font_init: file not found: ");
+ err_puts(path);
+ str_clean(&font->path);
+ return NULL;
+ }
+ assert(glGetError() == GL_NO_ERROR);
+ if (FT_New_Face(g_ft, font->real_path.ptr.ps8, 0, &font->ft_face)) {
+ err_write_1("gl_font_init: error loading font: ");
+ err_puts(font->real_path.ptr.ps8);
+ str_clean(&font->path);
+ str_clean(&font->real_path);
+ return NULL;
+ }
+ return font;
+}
+
+void gl_font_set_size (s_gl_font *font, f64 point_size,
+ f64 pixel_per_point)
+{
+ f64 size;
+ size = point_size * pixel_per_point;
+ FT_Set_Pixel_Sizes(font->ft_face, 0, size);
+}
diff --git a/libc3/window/sdl2/gl_font.h b/libc3/window/sdl2/gl_font.h
new file mode 100644
index 0000000..1ab8a96
--- /dev/null
+++ b/libc3/window/sdl2/gl_font.h
@@ -0,0 +1,28 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#ifndef 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 s8 *path);
+
+/* Operators. */
+void gl_font_set_size (s_gl_font *font, f64 size, f64 pixels_per_point);
+
+#endif /* GL_FONT_H */
diff --git a/libc3/window/sdl2/gl_ft2.h b/libc3/window/sdl2/gl_ft2.h
new file mode 100644
index 0000000..24feaa2
--- /dev/null
+++ b/libc3/window/sdl2/gl_ft2.h
@@ -0,0 +1,30 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#ifndef GL_FT2_H
+#define GL_FT2_H
+
+#include "types.h"
+
+/* 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 s8 *path);
+
+/* Operators. */
+void gl_font_set_size (s_gl_font *font, f64 size, f64 ppp);
+
+/* Observers */
+GLuint gl_font_render_to_texture (const s_gl_font *font,
+ const s_str *str);
+
+#endif /* GL_FT2_H */
diff --git a/libc3/window/sdl2/gl_text.c b/libc3/window/sdl2/gl_text.c
new file mode 100644
index 0000000..525103c
--- /dev/null
+++ b/libc3/window/sdl2/gl_text.c
@@ -0,0 +1,254 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#include <libc3/c3.h>
+#include "gl_object.h"
+#include "gl_point_2d.h"
+#include "gl_point_3d.h"
+#include "gl_text.h"
+#include "gl_triangle.h"
+
+void gl_text_clean (s_gl_text *text)
+{
+ gl_object_clean(&text->object);
+ str_clean(&text->str);
+ glDeleteTextures(1, &text->texture);
+}
+
+s_gl_text * gl_text_init (s_gl_text *text, const s_gl_font *font)
+{
+ uw dimension;
+ s_gl_text tmp = {0};
+ assert(glGetError() == GL_NO_ERROR);
+ tmp.font = font;
+ *text = tmp;
+ glGenTextures(1, &text->texture);
+ assert(glGetError() == GL_NO_ERROR);
+ gl_object_init(&text->object);
+ dimension = 4;
+ array_init(&text->object.vertex, sym_1("GL.Vertex"), 1,
+ &dimension);
+ dimension = 2;
+ array_init(&text->object.triangle, sym_1("GL.Triangle"), 1,
+ &dimension);
+ return text;
+}
+
+s_gl_text * gl_text_init_1 (s_gl_text *text, const s_gl_font *font,
+ const s8 *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};
+ tmp.font = font;
+ if (! str_init_copy(&tmp.str, str))
+ return NULL;
+ *text = tmp;
+ return text;
+}
+
+void gl_text_render (const s_gl_text *text)
+{
+ assert(text);
+ assert(glGetError() == GL_NO_ERROR);
+ gl_object_render(&text->object);
+}
+
+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;
+ const s_gl_font *font;
+ FT_UInt glyph_index;
+ uw i;
+ uw j;
+ f64 max_height = 0.0;
+ FT_UInt prev_glyph_index = 0;
+ s_str s;
+ f64 total_width = 0.0;
+ 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;
+ s = text->str;
+ while (str_read_character_utf8(&s, &c) > 0) {
+ glyph_index = FT_Get_Char_Index(font->ft_face, c);
+ if (prev_glyph_index && glyph_index) {
+ FT_Get_Kerning(font->ft_face, prev_glyph_index, glyph_index,
+ FT_KERNING_DEFAULT, &delta);
+ total_width += (f64) delta.x / (1 << 6);
+ }
+ if (FT_Load_Glyph(font->ft_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;
+ }
+ total_width += font->ft_face->glyph->bitmap.width;
+ max_height = (font->ft_face->glyph->bitmap.rows > max_height) ?
+ font->ft_face->glyph->bitmap.rows : max_height;
+ prev_glyph_index = glyph_index;
+ }
+ data_w = ceil(total_width);
+ data_h = ceil(max_height);
+ data_size = data_w * data_h;
+ data = calloc(4, data_size);
+ f64 x = 0;
+ prev_glyph_index = 0;
+ s = text->str;
+ while (str_read_character_utf8(&s, &c) > 0) {
+ glyph_index = FT_Get_Char_Index(font->ft_face, c);
+
+ // Apply kerning (adjust spacing between characters)
+ if (prev_glyph_index && glyph_index) {
+ FT_Vector delta;
+ FT_Get_Kerning(font->ft_face, prev_glyph_index, glyph_index,
+ FT_KERNING_DEFAULT, &delta);
+ x += (f64) delta.x / (1 << 6);
+ }
+ if (FT_Load_Glyph(font->ft_face, glyph_index, FT_LOAD_RENDER)) {
+ continue;
+ }
+ FT_GlyphSlot glyph;
+ glyph = font->ft_face->glyph;
+ i = 0;
+ while (i < glyph->bitmap.width) {
+ j = 0;
+ while (j < glyph->bitmap.rows) {
+ data_x = round(x) + i;
+ data_y = j + glyph->bitmap_top;
+ data_pixel = data + (data_y * data_w + data_x) * 4;
+ u8 value = glyph->bitmap.buffer[j * glyph->bitmap.width + i];
+ data_pixel[0] = value;
+ data_pixel[1] = value;
+ data_pixel[2] = value;
+ data_pixel[3] = value;
+ j++;
+ }
+ i++;
+ }
+ x += glyph->bitmap.width;
+ 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);
+ free(data);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ text->w = data_w;
+ text->h = data_h;
+ 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 s8 *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(p);
+ 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)
+{
+ s_gl_vertex *vertex;
+ s_gl_triangle *triangle;
+ if (! gl_text_render_to_texture(text))
+ return false;
+ vertex = text->object.vertex.data;
+ gl_point_3d_init(&vertex[0].position, 0.0, text->h, 0.0);
+ gl_point_3d_init(&vertex[0].normal, 0.0, 0.0, -1.0);
+ gl_point_2d_init(&vertex[0].tex_coord, 0.0, 1.0);
+ gl_point_3d_init(&vertex[1].position, 0.0, 0.0, 0.0);
+ gl_point_3d_init(&vertex[1].normal, 0.0, 0.0, -1.0);
+ gl_point_2d_init(&vertex[1].tex_coord, 0.0, 0.0);
+ gl_point_3d_init(&vertex[2].position, text->w, text->h, 0.0);
+ gl_point_3d_init(&vertex[2].normal, 0.0, 0.0, -1.0);
+ gl_point_2d_init(&vertex[2].tex_coord, 1.0, 1.0);
+ gl_point_3d_init(&vertex[3].position, text->w, 0.0, 0.0);
+ gl_point_3d_init(&vertex[3].normal, 0.0, 0.0, -1.0);
+ gl_point_2d_init(&vertex[3].tex_coord, 1.0, 0.0);
+ triangle = text->object.triangle.data;
+ gl_triangle_init(triangle + 0, 0, 1, 2);
+ gl_triangle_init(triangle + 1, 1, 3, 2);
+ return true;
+}
+
+bool gl_text_update_1 (s_gl_text *text, const s8 *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/libc3/window/sdl2/gl_text.h b/libc3/window/sdl2/gl_text.h
new file mode 100644
index 0000000..835bfcd
--- /dev/null
+++ b/libc3/window/sdl2/gl_text.h
@@ -0,0 +1,40 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#ifndef 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 s8 *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 s8 *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 s8 *p);
+bool gl_text_update_buf (s_gl_text *text, s_buf *buf);
+
+/* Observers. */
+void gl_text_render (const s_gl_text *text);
+
+#endif /* GL_TEXT_H */
diff --git a/libc3/window/sdl2/gl_triangle.c b/libc3/window/sdl2/gl_triangle.c
new file mode 100644
index 0000000..6a43a4c
--- /dev/null
+++ b/libc3/window/sdl2/gl_triangle.c
@@ -0,0 +1,23 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#include "gl_triangle.h"
+
+s_gl_triangle * gl_triangle_init (s_gl_triangle *triangle, u32 a, u32 b,
+ u32 c)
+{
+ assert(triangle);
+ triangle->a = a;
+ triangle->b = b;
+ triangle->c = c;
+ return triangle;
+}
diff --git a/libc3/window/sdl2/gl_triangle.h b/libc3/window/sdl2/gl_triangle.h
new file mode 100644
index 0000000..869ea78
--- /dev/null
+++ b/libc3/window/sdl2/gl_triangle.h
@@ -0,0 +1,21 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#ifndef GL_TRIANGLE_H
+#define GL_TRIANGLE_H
+
+#include "types.h"
+
+s_gl_triangle * gl_triangle_init (s_gl_triangle *triangle, u32 a, u32 b,
+ u32 c);
+
+#endif /* GL_TRIANGLE_H */
diff --git a/libc3/window/sdl2/sdl2_font.c b/libc3/window/sdl2/sdl2_font.c
deleted file mode 100644
index c5d8423..0000000
--- a/libc3/window/sdl2/sdl2_font.c
+++ /dev/null
@@ -1,65 +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.
- */
-#include <libc3/c3.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/libc3/window/sdl2/sdl2_font.h b/libc3/window/sdl2/sdl2_font.h
deleted file mode 100644
index c8a957c..0000000
--- a/libc3/window/sdl2/sdl2_font.h
+++ /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.
- */
-#ifndef LIBC3_WINDOW_SDL2_SDL2_FONT_H
-#define LIBC3_WINDOW_SDL2_SDL2_FONT_H
-
-#include <assert.h>
-#include <err.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 /* LIBC3_WINDOW_SDL2_SDL2_FONT_H */
diff --git a/libc3/window/sdl2/sources.mk b/libc3/window/sdl2/sources.mk
index 20595df..0c7ee2b 100644
--- a/libc3/window/sdl2/sources.mk
+++ b/libc3/window/sdl2/sources.mk
@@ -2,13 +2,16 @@
HEADERS = \
"gl_camera.h" \
"gl_cylinder.h" \
+ "gl_font.h" \
+ "gl_ft2.h" \
"gl_matrix_3d.h" \
"gl_matrix_4d.h" \
"gl_object.h" \
+ "gl_ortho.h" \
"gl_point_2d.h" \
"gl_point_3d.h" \
"gl_sphere.h" \
- "sdl2_font.h" \
+ "gl_text.h" \
"sdl2_sprite.h" \
"types.h" \
"window_sdl2.h" \
@@ -16,13 +19,14 @@ HEADERS = \
SOURCES = \
"gl_camera.c" \
"gl_cylinder.c" \
+ "gl_font.c" \
"gl_matrix_4d.c" \
"gl_object.c" \
"gl_ortho.c" \
"gl_point_2d.c" \
"gl_point_3d.c" \
"gl_sphere.c" \
- "sdl2_font.c" \
+ "gl_text.c" \
"sdl2_sprite.c" \
"window_sdl2.c" \
diff --git a/libc3/window/sdl2/sources.sh b/libc3/window/sdl2/sources.sh
index eae48ec..8080ffa 100644
--- a/libc3/window/sdl2/sources.sh
+++ b/libc3/window/sdl2/sources.sh
@@ -1,3 +1,3 @@
# sources.sh generated by update_sources
-HEADERS='gl_camera.h gl_cylinder.h gl_matrix_3d.h gl_matrix_4d.h gl_object.h gl_point_2d.h gl_point_3d.h gl_sphere.h sdl2_font.h sdl2_sprite.h types.h window_sdl2.h '
-SOURCES='gl_camera.c gl_cylinder.c gl_matrix_4d.c gl_object.c gl_ortho.c gl_point_2d.c gl_point_3d.c gl_sphere.c sdl2_font.c sdl2_sprite.c window_sdl2.c '
+HEADERS='gl_camera.h gl_cylinder.h gl_font.h gl_ft2.h gl_matrix_3d.h gl_matrix_4d.h gl_object.h gl_ortho.h gl_point_2d.h gl_point_3d.h gl_sphere.h gl_text.h sdl2_sprite.h types.h window_sdl2.h '
+SOURCES='gl_camera.c gl_cylinder.c gl_font.c gl_matrix_4d.c gl_object.c gl_ortho.c gl_point_2d.c gl_point_3d.c gl_sphere.c gl_text.c sdl2_sprite.c window_sdl2.c '
diff --git a/libc3/window/sdl2/types.h b/libc3/window/sdl2/types.h
index 42073c0..0d366f6 100644
--- a/libc3/window/sdl2/types.h
+++ b/libc3/window/sdl2/types.h
@@ -20,13 +20,15 @@
#include <GL/glew.h>
#include <SDL.h>
-#include <FTGL/ftgl.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
#include <png.h>
#include <libc3/types.h>
#include "../types.h"
typedef struct gl_camera s_gl_camera;
typedef struct gl_cylinder s_gl_cylinder;
+typedef struct gl_font s_gl_font;
typedef struct gl_matrix_3d s_gl_matrix_3d;
typedef struct gl_matrix_4d s_gl_matrix_4d;
typedef struct gl_object s_gl_object;
@@ -34,9 +36,9 @@ typedef struct gl_ortho s_gl_ortho;
typedef struct gl_point_2d s_gl_point_2d;
typedef struct gl_point_3d s_gl_point_3d;
typedef struct gl_sphere s_gl_sphere;
+typedef struct gl_text s_gl_text;
typedef struct gl_triangle s_gl_triangle;
typedef struct gl_vertex s_gl_vertex;
-typedef struct sdl2_font s_sdl2_font;
typedef struct sdl2_sprite s_sdl2_sprite;
typedef struct rgb s_rgb;
typedef struct rgba s_rgba;
@@ -75,15 +77,12 @@ typedef bool (*f_window_sdl2_sequence_render) (s_sequence *seq,
typedef void (*f_window_sdl2_unload) (s_window_sdl2 *window);
/* 1 */
-struct gl_point_2d {
- f64 x;
- f64 y;
-};
-
-struct gl_point_3d {
- f64 x;
- f64 y;
- f64 z;
+struct gl_font {
+ FT_Face ft_face;
+ f64 point_size;
+ f64 pixel_per_point;
+ s_str path;
+ s_str real_path;
};
struct gl_matrix_3d {
@@ -126,6 +125,26 @@ struct gl_object {
u32 gl_ebo;
};
+struct gl_point_2d {
+ f64 x;
+ f64 y;
+};
+
+struct gl_point_3d {
+ f64 x;
+ f64 y;
+ f64 z;
+};
+
+struct gl_text {
+ s_gl_object object;
+ const s_gl_font *font;
+ s_str str;
+ uw w;
+ uw h;
+ GLuint texture;
+};
+
struct gl_triangle {
u32 a;
u32 b;
@@ -145,14 +164,6 @@ struct rgba {
f64 a;
};
-struct sdl2_font {
- FTGLfont *ftgl_font;
- u32 size;
- u32 dpi;
- s_str path;
- s_str real_path;
-};
-
/* Subtype of s_window. See libc3/window/types.h */
struct window_sdl2 {
sw x;