aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2021-11-16 02:19:46 +0100
committerdec05eba <dec05eba@protonmail.com>2021-11-16 02:19:46 +0100
commitdcc00b359e313166f7f155bddc5cebc336c744b7 (patch)
treec3f83253f63467416d4b57c20faf73b683761678 /src
parent4c46bd7916ba692d75c5ee94099151b81695c48e (diff)
Text: add function to get character position by index, use same character loop everywhere
Diffstat (limited to 'src')
-rw-r--r--src/graphics/text.c150
1 files changed, 104 insertions, 46 deletions
diff --git a/src/graphics/text.c b/src/graphics/text.c
index ea60b6a..cd9d0d9 100644
--- a/src/graphics/text.c
+++ b/src/graphics/text.c
@@ -8,18 +8,11 @@
#define TAB_WIDTH 4
-static float max_float(float a, float b) {
- return a >= b ? a : b;
-}
-
-static mgl_vec2f mgl_text_calculate_bounds(mgl_text *self) {
- mgl_vec2f bounds;
- bounds.x = 0.0f;
- bounds.y = self->font->character_size;
-
- /* TODO: Combine this with the loop in mgl_text_draw */
+/* Return false to stop the loop. |glyph| is not valid if codepoint is '\n' */
+typedef bool (*codepoint_loop_callback)(size_t codepoint_index, uint32_t codepoint, const mgl_font_glyph *glyph, void *userdata);
+static void mgl_text_for_each_codepoint(const mgl_text *self, codepoint_loop_callback callback, void *userdata) {
mgl_font_glyph glyph;
- float width = 0.0f;
+ size_t codepoint_index = 0;
for(size_t i = 0; i < self->text_size;) {
unsigned char *cp = (unsigned char*)&self->text[i];
uint32_t codepoint;
@@ -31,22 +24,57 @@ static mgl_vec2f mgl_text_calculate_bounds(mgl_text *self) {
if(codepoint == '\t') {
if(mgl_font_get_glyph(self->font, ' ', &glyph) == 0) {
- width += (glyph.advance * TAB_WIDTH);
- bounds.x = max_float(bounds.x, width);
+ if(!callback(codepoint_index, codepoint, &glyph, userdata))
+ return;
}
} else if(codepoint == '\n') {
- width = 0.0f;
- bounds.y += self->font->character_size;
+ if(!callback(codepoint_index, codepoint, &glyph, userdata))
+ return;
} else {
if(mgl_font_get_glyph(self->font, codepoint, &glyph) == 0) {
- width += glyph.advance;
- bounds.x = max_float(bounds.x, width);
+ if(!callback(codepoint_index, codepoint, &glyph, userdata))
+ return;
}
}
i += clen;
+ ++codepoint_index;
+ }
+}
+
+static float max_float(float a, float b) {
+ return a >= b ? a : b;
+}
+
+typedef struct {
+ mgl_vec2f bounds;
+ float line_width;
+ const mgl_font *font;
+} CalculateBoundsUserdata;
+
+static bool calculate_bounds_callback(size_t codepoint_index, uint32_t codepoint, const mgl_font_glyph *glyph, void *userdata) {
+ (void)codepoint_index;
+ CalculateBoundsUserdata *calculate_bounds_userdata = userdata;
+ if(codepoint == '\t') {
+ calculate_bounds_userdata->line_width += (glyph->advance * TAB_WIDTH);
+ calculate_bounds_userdata->bounds.x = max_float(calculate_bounds_userdata->bounds.x, calculate_bounds_userdata->line_width);
+ } else if(codepoint == '\n') {
+ calculate_bounds_userdata->line_width = 0.0f;
+ calculate_bounds_userdata->bounds.y += calculate_bounds_userdata->font->character_size;
+ } else {
+ calculate_bounds_userdata->line_width += glyph->advance;
+ calculate_bounds_userdata->bounds.x = max_float(calculate_bounds_userdata->bounds.x, calculate_bounds_userdata->line_width);
}
+ return true;
+}
- return bounds;
+static mgl_vec2f mgl_text_calculate_bounds(mgl_text *self) {
+ CalculateBoundsUserdata calculate_bounds_userdata;
+ calculate_bounds_userdata.bounds.x = 0.0f;
+ calculate_bounds_userdata.bounds.y = self->font->character_size;
+ calculate_bounds_userdata.line_width = 0.0f;
+ calculate_bounds_userdata.font = self->font;
+ mgl_text_for_each_codepoint(self, calculate_bounds_callback, &calculate_bounds_userdata);
+ return calculate_bounds_userdata.bounds;
}
void mgl_text_init(mgl_text *self, mgl_font *font, const char *str, size_t str_size) {
@@ -97,7 +125,38 @@ mgl_vec2f mgl_text_get_bounds(const mgl_text *self) {
return self->bounds;
}
-static void mgl_text_draw_glyph(mgl_context *context, mgl_font_glyph *glyph, mgl_vec2i position) {
+typedef struct {
+ mgl_vec2i position;
+ const mgl_text *text;
+ size_t index;
+} FindCharacterPosUserdata;
+
+static bool find_character_pos_callback(size_t codepoint_index, uint32_t codepoint, const mgl_font_glyph *glyph, void *userdata) {
+ FindCharacterPosUserdata *find_character_pos_userdata = userdata;
+ if(codepoint_index >= find_character_pos_userdata->index)
+ return false;
+
+ if(codepoint == '\t') {
+ find_character_pos_userdata->position.x += (glyph->advance * TAB_WIDTH);
+ } else if(codepoint == '\n') {
+ find_character_pos_userdata->position.x = find_character_pos_userdata->text->position.x;
+ find_character_pos_userdata->position.y += find_character_pos_userdata->text->font->character_size;
+ } else {
+ find_character_pos_userdata->position.x += glyph->advance;
+ }
+ return true;
+}
+
+mgl_vec2f mgl_text_find_character_pos(mgl_text *self, size_t index) {
+ FindCharacterPosUserdata find_character_pos_userdata;
+ find_character_pos_userdata.position = (mgl_vec2i){ self->position.x, self->position.y };
+ find_character_pos_userdata.text = self;
+ find_character_pos_userdata.index = index;
+ mgl_text_for_each_codepoint(self, find_character_pos_callback, &find_character_pos_userdata);
+ return (mgl_vec2f){ find_character_pos_userdata.position.x, find_character_pos_userdata.position.y };
+}
+
+static void mgl_text_draw_glyph(mgl_context *context, const mgl_font_glyph *glyph, mgl_vec2i position) {
context->gl.glTexCoord2f(glyph->texture_position.x, glyph->texture_position.y);
context->gl.glVertex3f(position.x + glyph->position.x, position.y + glyph->position.y, 0.0f);
@@ -111,43 +170,42 @@ static void mgl_text_draw_glyph(mgl_context *context, mgl_font_glyph *glyph, mgl
context->gl.glVertex3f(position.x + glyph->position.x, position.y + glyph->position.y + glyph->size.y, 0.0f);
}
+typedef struct {
+ mgl_vec2i position;
+ const mgl_text *text;
+ mgl_context *context;
+} TextDrawUserdata;
+
+static bool text_draw_callback(size_t codepoint_index, uint32_t codepoint, const mgl_font_glyph *glyph, void *userdata) {
+ (void)codepoint_index;
+ TextDrawUserdata *text_draw_userdata = userdata;
+ if(codepoint == '\t') {
+ text_draw_userdata->position.x += (glyph->advance * TAB_WIDTH);
+ } else if(codepoint == '\n') {
+ text_draw_userdata->position.x = text_draw_userdata->text->position.x;
+ text_draw_userdata->position.y += text_draw_userdata->text->font->character_size;
+ } else {
+ mgl_text_draw_glyph(text_draw_userdata->context, glyph, text_draw_userdata->position);
+ text_draw_userdata->position.x += glyph->advance;
+ }
+ return true;
+}
+
/* TODO: Use opengl buffer object instead */
/* TODO: Cache texture bind to not bind texture if its already bound and do not bind texture 0 */
void mgl_text_draw(mgl_context *context, mgl_text *text) {
if(!text->text || text->text_size == 0 || !text->font)
return;
- mgl_font_glyph glyph;
- mgl_vec2i position = (mgl_vec2i){ text->position.x, text->position.y };
- position.y += text->font->character_size;
+ TextDrawUserdata text_draw_userdata;
+ text_draw_userdata.position = (mgl_vec2i){ text->position.x, text->position.y + text->font->character_size };
+ text_draw_userdata.text = text;
+ text_draw_userdata.context = context;
context->gl.glColor4ub(text->color.r, text->color.g, text->color.b, text->color.a);
mgl_texture_use(&text->font->texture);
context->gl.glBegin(GL_QUADS);
- for(size_t i = 0; i < text->text_size;) {
- unsigned char *cp = (unsigned char*)&text->text[i];
- uint32_t codepoint;
- size_t clen;
- if(!mgl_utf8_decode(cp, text->text_size - i, &codepoint, &clen)) {
- codepoint = *cp;
- clen = 1;
- }
-
- if(codepoint == '\t') {
- if(mgl_font_get_glyph(text->font, ' ', &glyph) == 0) {
- position.x += (glyph.advance * TAB_WIDTH);
- }
- } else if(codepoint == '\n') {
- position.x = text->position.x;
- position.y += text->font->character_size;
- } else {
- if(mgl_font_get_glyph(text->font, codepoint, &glyph) == 0) {
- mgl_text_draw_glyph(context, &glyph, position);
- position.x += glyph.advance;
- }
- }
- i += clen;
- }
+ mgl_text_for_each_codepoint(text, text_draw_callback, &text_draw_userdata);
context->gl.glEnd();
mgl_texture_use(NULL);
}