summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-11-25 11:24:14 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2020-11-25 11:24:14 -0500
commitc2f91a659c126d1fd5ee951bdf58540d9d39fd47 (patch)
treeb63cbf31f19ed2ed01eaf7cf7455033952679546
parent4e51199f1103d2d9daa563b63d0e8f22c36fbe8a (diff)
rendering a text buffer
-rw-r--r--buffer.c56
-rw-r--r--main.c9
-rw-r--r--text.c27
-rw-r--r--text.h10
-rw-r--r--unicode.h5
5 files changed, 86 insertions, 21 deletions
diff --git a/buffer.c b/buffer.c
index 78fcc1a..8641eb1 100644
--- a/buffer.c
+++ b/buffer.c
@@ -3,7 +3,9 @@
// blocks of a few thousand bytes. Block boundaries are not necessarily
// on character boundaries, so one block might have part of a UTF-8 character
// with the next block having the rest.
+#include "unicode.h"
#include "util.c"
+#include "text.h"
#define TEXT_BLOCK_MAX_SIZE 400
// Once two adjacent blocks are at most this big, combine them into
@@ -114,3 +116,57 @@ void text_buffer_free(TextBuffer *buffer) {
}
free(blocks);
}
+
+// Render the text buffer in the given rectangle
+void text_buffer_render(TextBuffer *buffer, Font *font, float box_x, float box_y, float box_w, float box_h) {
+ mbstate_t mbstate = {0};
+ uint nblocks = buffer->nblocks;
+ TextBlock *blocks = buffer->blocks;
+ text_chars_begin(font);
+ TextRenderState text_state = {
+ .x = box_x, .y = box_y,
+ .edge_right = box_x+box_w,
+ .edge_bottom = box_y+box_h
+ };
+
+ for (uint block_idx = 0; block_idx < nblocks; ++block_idx) {
+ TextBlock *block = &blocks[block_idx];
+ char *p = block->contents, *end = p + block->len;
+ while (p != end) {
+ char32_t c;
+ size_t n = mbrtoc32(&c, p, (size_t)(end - p), &mbstate);
+ if (n == 0) {
+ // null character
+ c = UNICODE_BOX_CHARACTER;
+ ++p;
+ } else if (n == (size_t)(-3)) {
+ // no bytes consumed, but a character was produced
+ } else if (n == (size_t)(-2)) {
+ // incomplete character at end of block.
+ c = 0;
+ p = end;
+ } else if (n == (size_t)(-1)) {
+ // invalid UTF-8
+ c = UNICODE_BOX_CHARACTER;
+ ++p;
+ } else {
+ p += n;
+ }
+ switch (c) {
+ case L'\n':
+ text_state.x = box_x;
+ text_state.y -= text_font_char_height(font);
+ break;
+ case L'\r': break; // for CRLF line endings
+ case L'\t':
+ for (int i = 0; i < 4; ++i)
+ text_render_char(font, L' ', &text_state);
+ break;
+ default:
+ text_render_char(font, c, &text_state);
+ break;
+ }
+ }
+ }
+ text_chars_end(font);
+}
diff --git a/main.c b/main.c
index 063f7eb..f2812f5 100644
--- a/main.c
+++ b/main.c
@@ -38,7 +38,8 @@ int main(void) {
if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) < 0)
die("%s", SDL_GetError());
- SDL_Window *window = SDL_CreateWindow("ted", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1280, 720, SDL_WINDOW_SHOWN|SDL_WINDOW_OPENGL);
+ SDL_Window *window = SDL_CreateWindow("ted", SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED, 1280, 720, SDL_WINDOW_SHOWN|SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
if (!window)
die("%s", SDL_GetError());
@@ -51,7 +52,7 @@ int main(void) {
SDL_GL_SetSwapInterval(1); // vsync
- Font *font = text_font_load("assets/font.ttf", 24);
+ Font *font = text_font_load("assets/font.ttf", 16);
if (!font) {
die("Couldn't load font: %s", text_get_err());
}
@@ -81,6 +82,7 @@ int main(void) {
int window_width = 0, window_height = 0;
SDL_GetWindowSize(window, &window_width, &window_height);
+ float window_widthf = (float)window_width, window_heightf = (float)window_height;
// set up GL
glEnable(GL_BLEND);
@@ -93,7 +95,8 @@ int main(void) {
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1,1,1);
- text_render(font, "hellσ! öθ☺", 50, 50);
+ //text_render(font, "hellσ! öθ☺", 50, 50);
+ text_buffer_render(&text_buffer, font, 50, window_heightf-50, window_widthf-100, window_heightf-100);
if (text_has_err()) {
printf("Text error: %s\n", text_get_err());
break;
diff --git a/text.c b/text.c
index 258af36..ddd7cdc 100644
--- a/text.c
+++ b/text.c
@@ -1,5 +1,6 @@
#include "base.h"
#include "text.h"
+#include "unicode.h"
#define STB_TRUETYPE_IMPLEMENTATION
#define STBTT_STATIC
no_warn_start
@@ -8,7 +9,6 @@ no_warn_end
#include <stdlib.h>
#include <GL/gl.h>
-#define UNICODE_CODE_POINTS 0x110000 // number of Unicode code points
// We split up code points into a bunch of pages, so we don't have to load all of the font at
// once into one texture.
#define CHAR_PAGE_SIZE 2048
@@ -136,9 +136,9 @@ Font *text_font_load(char const *ttf_filename, float font_size) {
return font;
}
-typedef struct {
- float x, y;
-} TextRenderState;
+float text_font_char_height(Font *font) {
+ return font->char_height;
+}
static void text_render_with_page(Font *font, int page) {
if (font->curr_page != page) {
@@ -164,14 +164,14 @@ void text_chars_end(Font *font) {
font->curr_page = -1;
}
-static void text_render_char_internal(Font *font, char32_t c, TextRenderState *state) {
+void text_render_char(Font *font, char32_t c, TextRenderState *state) {
if (c >= 0x30000 && c < 0xE0000){
// these Unicode code points are currently unassigned. replace them with a Unicode box.
// (specifically, we don't want to use extra memory for pages which
// won't even have any valid characters in them)
- c = 0x2610;
+ c = UNICODE_BOX_CHARACTER;
}
- if (c >= UNICODE_CODE_POINTS) c = 0x2610; // code points this big should never appear in valid Unicode
+ if (c >= UNICODE_CODE_POINTS) c = UNICODE_BOX_CHARACTER; // code points this big should never appear in valid Unicode
uint page = c / CHAR_PAGE_SIZE;
uint index = c % CHAR_PAGE_SIZE;
text_render_with_page(font, (int)page);
@@ -191,13 +191,6 @@ static void text_render_char_internal(Font *font, char32_t c, TextRenderState *s
}
}
-void text_render_char(Font *font, char32_t c, float *x, float *y) {
- TextRenderState state = {*x, *y};
- text_render_char_internal(font, c, &state);
- *x = state.x;
- *y = state.y;
-}
-
static void text_render_internal(Font *font, char const *text, float *x, float *y) {
mbstate_t mbstate = {0};
TextRenderState render_state = {*x, *y};
@@ -208,18 +201,18 @@ static void text_render_internal(Font *font, char const *text, float *x, float *
size_t ret = mbrtoc32(&c, text, (size_t)(end - text), &mbstate);
if (ret == 0) break;
if (ret == (size_t)(-2)) { // incomplete multi-byte character
- text_render_char_internal(font, '?', &render_state);
+ text_render_char(font, '?', &render_state);
text = end; // done reading text
} else if (ret == (size_t)(-1)) {
// invalid UTF-8; skip this byte
- text_render_char_internal(font, '?', &render_state);
+ text_render_char(font, '?', &render_state);
++text;
} else {
if (ret != (size_t)(-3))
text += ret; // character consists of `ret` bytes
switch (c) {
default:
- text_render_char_internal(font, (char32_t)c, &render_state);
+ text_render_char(font, (char32_t)c, &render_state);
break;
}
}
diff --git a/text.h b/text.h
index ad18ef3..45cc6bb 100644
--- a/text.h
+++ b/text.h
@@ -10,6 +10,12 @@
typedef struct Font Font;
+typedef struct {
+ float x, y;
+ // points at which the text should be cut off in the x and y directions
+ float edge_right, edge_bottom;
+} TextRenderState;
+
extern bool text_has_err(void);
// Get the current error. Errors will NOT be overwritten with newer errors.
extern char const *text_get_err(void);
@@ -17,6 +23,8 @@ extern char const *text_get_err(void);
extern void text_clear_err(void);
// Load a TTF font found in ttf_filename with the given font size (character pixel height)
extern Font *text_font_load(char const *ttf_filename, float font_size);
+// Height of a character of this font in pixels.
+extern float text_font_char_height(Font *font);
// Render some UTF-8 text to the screen (simple interface).
extern void text_render(Font *font, char const *text, float x, float y);
// Get the dimensions of some text.
@@ -26,7 +34,7 @@ extern void text_chars_begin(Font *font);
// Finish writing characters.
extern void text_chars_end(Font *font);
// Render a single character.
-extern void text_render_char(Font *font, char32_t c, float *x, float *y);
+extern void text_render_char(Font *font, char32_t c, TextRenderState *state);
// Free memory used by font.
extern void text_font_free(Font *font);
diff --git a/unicode.h b/unicode.h
new file mode 100644
index 0000000..387c08d
--- /dev/null
+++ b/unicode.h
@@ -0,0 +1,5 @@
+#ifndef UNICODE_H_
+#define UNICODE_H_
+#define UNICODE_BOX_CHARACTER 0x2610
+#define UNICODE_CODE_POINTS 0x110000 // number of Unicode code points
+#endif