#include "../../include/mgl/graphics/text.h" #include "../../include/mgl/graphics/font.h" #include "../../include/mgl/system/utf8.h" #include "../../include/mgl/mgl.h" #include #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 */ mgl_font_glyph glyph; float width = 0.0f; for(size_t i = 0; i < self->text_size;) { unsigned char *cp = (unsigned char*)&self->text[i]; uint32_t codepoint; size_t clen; if(!mgl_utf8_decode(cp, self->text_size - i, &codepoint, &clen)) { codepoint = *cp; clen = 1; } if(codepoint == '\t') { if(mgl_font_get_glyph(self->font, ' ', &glyph) == 0) { width += (glyph.advance * TAB_WIDTH); bounds.x = max_float(bounds.x, width); } } else if(codepoint == '\n') { width = 0.0f; bounds.y += self->font->character_size; } else { if(mgl_font_get_glyph(self->font, codepoint, &glyph) == 0) { width += glyph.advance; bounds.x = max_float(bounds.x, width); } } i += clen; } return bounds; } void mgl_text_init(mgl_text *self, mgl_font *font, const char *str, size_t str_size) { self->font = font; self->color = (mgl_color){ 255, 255, 255, 255 }; self->position = (mgl_vec2f){ 0.0f, 0.0f }; self->text = NULL; self->text_size = 0; mgl_text_set_string(self, str, str_size); } void mgl_text_deinit(mgl_text *self) { self->font = NULL; self->position = (mgl_vec2f){ 0.0f, 0.0f }; self->text = NULL; self->text_size = 0; self->bounds = (mgl_vec2f){ 0.0f, 0.0f }; } void mgl_text_set_string(mgl_text *self, const char *str, size_t str_size) { self->text = str; self->text_size = str_size; if(self->text && self->text_size > 0 && self->font) self->bounds = mgl_text_calculate_bounds(self); else self->bounds = (mgl_vec2f){ 0.0f, 0.0f }; } void mgl_text_set_font(mgl_text *self, mgl_font *font) { self->font = font; if(self->font) { if(self->bounds.x < 0.001f && self->bounds.y < 0.001f && self->text && self->text_size > 0) self->bounds = mgl_text_calculate_bounds(self); } else { self->bounds = (mgl_vec2f){ 0.0f, 0.0f }; } } void mgl_text_set_position(mgl_text *self, mgl_vec2f position) { self->position = position; } void mgl_text_set_color(mgl_text *self, mgl_color color) { self->color = color; } 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_vec2f 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); context->gl.glTexCoord2f(glyph->texture_position.x + glyph->texture_size.x, glyph->texture_position.y); context->gl.glVertex3f(position.x + glyph->position.x + glyph->size.x, position.y + glyph->position.y, 0.0f); context->gl.glTexCoord2f(glyph->texture_position.x + glyph->texture_size.x, glyph->texture_position.y + glyph->texture_size.y); context->gl.glVertex3f(position.x + glyph->position.x + glyph->size.x, position.y + glyph->position.y + glyph->size.y, 0.0f); context->gl.glTexCoord2f(glyph->texture_position.x, glyph->texture_position.y + glyph->texture_size.y); context->gl.glVertex3f(position.x + glyph->position.x, position.y + glyph->position.y + glyph->size.y, 0.0f); } /* 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_vec2f position = text->position; position.y += text->font->character_size; context->gl.glColor4ub(text->color.r, text->color.g, text->color.b, text->color.a); context->gl.glBindTexture(GL_TEXTURE_2D, text->font->texture.id); 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; } context->gl.glEnd(); context->gl.glBindTexture(GL_TEXTURE_2D, 0); }