From 5e458dff3bcc832b0b28d83bd3ef482174d1dc09 Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Fri, 20 Nov 2020 22:28:38 -0500 Subject: more text rendering --- Makefile | 6 ++--- assets/font.ttf | Bin 0 -> 107848 bytes base.h | 22 +++++++++++++++ main.c | 5 ++++ text.c | 82 ++++++++++++++++++++++++++++++++++++++++++++------------ 5 files changed, 95 insertions(+), 20 deletions(-) create mode 100644 assets/font.ttf diff --git a/Makefile b/Makefile index 42064a0..e10bdc9 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ ALL_CFLAGS=$(CFLAGS) -Wall -Wextra -Wshadow -Wconversion -Wpedantic -pedantic -std=gnu11 \ -Wno-unused-function -Wno-fixed-enum-extension -Wimplicit-fallthrough -LIBS=-lSDL2 -lGL -ldl -DEBUG_CFLAGS=$(ALL_CFLAGS) $(LIBS) -DDEBUG -O0 -g +LIBS=-lSDL2 -lGL -ldl -lm +DEBUG_CFLAGS=$(ALL_CFLAGS) -DDEBUG -O0 -g ted: *.[ch] text.o - $(CC) main.c text.o -o $@ $(DEBUG_CFLAGS) + $(CC) main.c text.o -o $@ $(DEBUG_CFLAGS) $(LIBS) %.o: %.c $(CC) $< -c -o $@ $(DEBUG_CFLAGS) diff --git a/assets/font.ttf b/assets/font.ttf new file mode 100644 index 0000000..3560a3a Binary files /dev/null and b/assets/font.ttf differ diff --git a/base.h b/base.h index 92270bc..8327fdb 100644 --- a/base.h +++ b/base.h @@ -1,6 +1,10 @@ #ifndef BASE_H_ #define BASE_H_ +#ifndef DEBUG +#define NDEBUG 1 +#endif + #include #include #include @@ -34,4 +38,22 @@ typedef unsigned long ulong; #define no_warn_end #endif +#if DEBUG +#if __unix__ +#define debug_println printf +#else // __unix__ +static void debug_println(char const *fmt, ...) { + char buf[256]; + va_list args; + va_start(args, fmt); + vsprintf_s(buf, sizeof buf, fmt, args); + va_end(args); + OutputDebugStringA(buf); + OutputDebugStringA("\n"); +} +#endif // __unix__ +#else // DEBUG +#define debug_println(...) +#endif + #endif diff --git a/main.c b/main.c index 1d549a6..2353d08 100644 --- a/main.c +++ b/main.c @@ -3,6 +3,7 @@ no_warn_start #include no_warn_end #include +#include "text.h" static void die(char const *fmt, ...) { char buf[256] = {0}; @@ -38,6 +39,10 @@ int main(void) { SDL_GL_SetSwapInterval(1); // vsync + Font *font = text_font_load("assets/font.ttf", 12); + if (!font) { + die("Couldn't load font: %s", text_get_err()); + } bool quit = false; while (!quit) { diff --git a/text.c b/text.c index 19d62a2..7007ad6 100644 --- a/text.c +++ b/text.c @@ -1,27 +1,25 @@ #include "base.h" +#include "text.h" +#define STB_TRUETYPE_IMPLEMENTATION +#define STBTT_STATIC no_warn_start #include "stb_truetype.h" no_warn_end #include #include +#include -typedef struct { +struct Font { float char_height; - u32 nchars; GLuint texture; + u32 nchars; stbtt_bakedchar chars[]; -} Font; +}; static char text_err[200]; static void text_clear_err(void) { text_err[0] = '\0'; } -static void text_set_err(char const *fmt, ...) { - va_list args; - va_start(args, fmt); - vsnprintf(text_err, sizeof text_err - 1, fmt, args); - va_end(args); -} static bool text_has_err(void) { return text_err[0] != '\0'; @@ -31,6 +29,15 @@ char const *text_get_err(void) { return text_err; } +static void text_set_err(char const *fmt, ...) { + if (!text_has_err()) { + va_list args; + va_start(args, fmt); + vsnprintf(text_err, sizeof text_err - 1, fmt, args); + va_end(args); + } +} + Font *text_font_load(char const *ttf_filename, float font_size) { Font *font = NULL; u32 nchars = 128; @@ -42,30 +49,71 @@ Font *text_font_load(char const *ttf_filename, float font_size) { fseek(ttf_file, 0, SEEK_END); u32 file_size = (u32)ftell(ttf_file); if (file_size < (50UL<<20)) { // fonts aren't usually bigger than 50 MB - char *file_data = calloc(1, file_size); - Font *font = calloc(1, sizeof *font + nchars * sizeof *font->chars); + u8 *file_data = calloc(1, file_size); + font = calloc(1, sizeof *font + nchars * sizeof *font->chars); if (file_data && font) { - font->nchars = nchars; - font->char_height = font_size; - stbtt_ + if (fread(file_data, 1, file_size, ttf_file) == file_size) { + font->nchars = nchars; + font->char_height = font_size; + + for (int bitmap_width = 256, bitmap_height = 256; bitmap_width <= 4096; bitmap_width *= 2, bitmap_height *= 2) { + u8 *bitmap = calloc((size_t)bitmap_width, (size_t)bitmap_height); + if (bitmap) { + int err = stbtt_BakeFontBitmap(file_data, 0, font->char_height, bitmap, + bitmap_width, bitmap_height, 0, (int)font->nchars, font->chars); + if (err > 0) { + // font converted to bitmap successfully. + GLuint texture = 0; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, bitmap_width, bitmap_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, bitmap); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + #if DEBUG + debug_println("Loaded font %s with %dx%d bitmap.", ttf_filename, bitmap_width, bitmap_height); + #endif + font->texture = texture; + if (glGetError()) { + text_set_err("Couldn't create texture for font."); + } + } + } else { + text_set_err("Not enough memory for font bitmap."); + } + free(bitmap); + if (font->texture) { // if font loaded successfully + break; + } + } + if (!font->texture && !text_has_err()) { + text_set_err("Couldn't convert font to bitmap."); + } + } else { + text_set_err("Couldn't read font file.", ttf_filename); + } } else { text_set_err("Not enough memory for font."); } free(file_data); - if (text_has_err()) + if (text_has_err()) { free(font); + font = NULL; + } fclose(ttf_file); } else { text_set_err("Font file too big (%u megabytes).", (uint)(file_size >> 20)); } } else { - text_set_err("Couldn't open font file: %s.", ttf_filename); + text_set_err("Couldn't open font file.", ttf_filename); } - return NULL; + return font; } +#if 0 void text_render(Font *font, char const *text, float x, float y) { + } void text_get_size(Font *font, char const *text, float *width, float *height) { } +#endif -- cgit v1.2.3