From 128edda6c0f49cea5ccf0726695ae1d421c428af Mon Sep 17 00:00:00 2001 From: Nunuhara Cabbage Date: Tue, 10 May 2022 19:53:31 -0700 Subject: [PATCH] text: fix outline cropping issue Fix issue where outlines would get cropped when crossing the glyph texture boundary. This is accomplished by adding 4 border pixels to each glyph texture. --- include/gfx/gfx.h | 4 ++-- src/draw.c | 12 ++++++------ src/text.c | 47 ++++++++++++++++++++++++++++++----------------- 3 files changed, 38 insertions(+), 25 deletions(-) diff --git a/include/gfx/gfx.h b/include/gfx/gfx.h index 2d7d5cc..154e9ce 100644 --- a/include/gfx/gfx.h +++ b/include/gfx/gfx.h @@ -160,8 +160,8 @@ void gfx_copy_with_alpha_map(Texture *dst, int dx, int dy, Texture *src, int sx, void gfx_fill_with_alpha(Texture *dst, int x, int y, int w, int h, int r, int g, int b, int a); void gfx_copy_stretch_with_alpha_map(Texture *dst, int dx, int dy, int dw, int dh, Texture *src, int sx, int sy, int sw, int sh); void gfx_draw_glyph(Texture *dst, float dx, int dy, Texture *glyph, SDL_Color color, float scale_x, float bold_width); -void gfx_draw_glyph_to_pmap(Texture *dst, float dx, int dy, Texture *glyph, SDL_Color color, float scale_x); -void gfx_draw_glyph_to_amap(Texture *dst, float dx, int dy, Texture *glyph, float scale_x); +void gfx_draw_glyph_to_pmap(Texture *dst, float dx, int dy, Texture *glyph, Rectangle glyph_pos, SDL_Color color, float scale_x); +void gfx_draw_glyph_to_amap(Texture *dst, float dx, int dy, Texture *glyph, Rectangle glyph_pos, float scale_x); enum { FW_NORMAL = 400, diff --git a/src/draw.c b/src/draw.c index 7e62700..0afbb18 100644 --- a/src/draw.c +++ b/src/draw.c @@ -1027,11 +1027,11 @@ void gfx_draw_glyph(Texture *dst, float dx, int dy, Texture *glyph, SDL_Color co restore_blend_mode(); } -void gfx_draw_glyph_to_pmap(Texture *dst, float dx, int dy, Texture *glyph, SDL_Color color, float scale_x) +void gfx_draw_glyph_to_pmap(Texture *dst, float dx, int dy, Texture *glyph, Rectangle glyph_pos, SDL_Color color, float scale_x) { struct copy_data data = STRETCH_DATA( - dx, dy, glyph->w * scale_x, glyph->h, - 0, 0, glyph->w, glyph->h); + dx, dy, glyph_pos.w * scale_x, glyph_pos.h, + glyph_pos.x, glyph_pos.y, glyph_pos.w, glyph_pos.h); data.r = color.r / 255.0; data.g = color.g / 255.0; data.b = color.b / 255.0; @@ -1041,11 +1041,11 @@ void gfx_draw_glyph_to_pmap(Texture *dst, float dx, int dy, Texture *glyph, SDL_ restore_blend_mode(); } -void gfx_draw_glyph_to_amap(Texture *dst, float dx, int dy, Texture *glyph, float scale_x) +void gfx_draw_glyph_to_amap(Texture *dst, float dx, int dy, Texture *glyph, Rectangle glyph_pos, float scale_x) { struct copy_data data = STRETCH_DATA( - dx, dy, glyph->w * scale_x, glyph->h, - 0, 0, glyph->w, glyph->h); + dx, dy, glyph_pos.w * scale_x, glyph_pos.h, + glyph_pos.x, glyph_pos.y, glyph_pos.w, glyph_pos.h); data.r = 1.0; data.g = 1.0; data.b = 1.0; diff --git a/src/text.c b/src/text.c index cf6293e..09c67e2 100644 --- a/src/text.c +++ b/src/text.c @@ -53,8 +53,7 @@ enum font_weight { #define NR_FONT_WEIGHTS (WEIGHT_HEAVY+1) struct glyph { - float off_x; - float off_y; + Rectangle rect; Texture t[NR_FONT_WEIGHTS]; }; @@ -133,15 +132,22 @@ static struct font_size *get_font_size(enum font_face type, unsigned size) return fs; } +// NOTE: we create glyph textures slightly larger than necessary so that outlines +// aren't cut off at the texture boundary. +// FIXME: the outline rendering code should be fixed so this isn't necessary. +#define GLYPH_BORDER_SIZE 4 + // Convert a glyph rendered by FreeType to a block-sized texture. // Block size is size x 1.5*size (full-width) or size/2 x 1.5*size (half-width) -static void init_glyph_texture(Texture *dst, FT_Bitmap *glyph, int bitmap_top, int size, bool half_width) +static Rectangle init_glyph_texture(Texture *dst, FT_Bitmap *glyph, int bitmap_top, int size, bool half_width) { // calculate block size and offsets - int width = half_width ? size/2 : size; - int height = size + size/2; - int off_x = max(0, (width - (int)glyph->width) / 2); - int off_y = max(0, size - bitmap_top); + int block_width = (half_width ? size/2 : size); + int block_height = size + size/2; + int width = block_width + GLYPH_BORDER_SIZE*2; + int height = block_height + GLYPH_BORDER_SIZE*2; + int off_x = max(0, (block_width - (int)glyph->width) / 2) + GLYPH_BORDER_SIZE; + int off_y = max(0, size - bitmap_top) + GLYPH_BORDER_SIZE; uint8_t *bitmap = xcalloc(1, width * height); // Expand the glyph bitmap to block size @@ -155,6 +161,13 @@ static void init_glyph_texture(Texture *dst, FT_Bitmap *glyph, int bitmap_top, i // create texture from block-size bitmap gfx_init_texture_rmap(dst, width, height, bitmap); free(bitmap); + + return (Rectangle) { + .x = GLYPH_BORDER_SIZE, + .y = GLYPH_BORDER_SIZE, + .w = block_width, + .h = block_height + }; } static struct glyph *get_glyph(struct font_size *font_size, uint32_t code, bool half_width, enum font_weight weight) @@ -184,7 +197,8 @@ static struct glyph *get_glyph(struct font_size *font_size, uint32_t code, bool // create texture from bitmap FT_Bitmap *bitmap = &font->glyph->bitmap; if (bitmap->pixel_mode == FT_PIXEL_MODE_GRAY) { - init_glyph_texture(t, bitmap, font->glyph->bitmap_top, font_size->size, half_width); + glyph->rect = init_glyph_texture(t, bitmap, font->glyph->bitmap_top, + font_size->size, half_width); } else if (bitmap->pixel_mode == FT_PIXEL_MODE_MONO) { FT_Bitmap tmp; FT_Bitmap_New(&tmp); @@ -198,15 +212,14 @@ static struct glyph *get_glyph(struct font_size *font_size, uint32_t code, bool if (tmp.buffer[i]) tmp.buffer[i] = 255; } - init_glyph_texture(t, &tmp, font->glyph->bitmap_top, font_size->size, half_width); + glyph->rect = init_glyph_texture(t, &tmp, font->glyph->bitmap_top, + font_size->size, half_width); FT_Bitmap_Done(ft_lib, &tmp); } else { WARNING("Font returned glyph with unsupported pixel mode"); return NULL; } - glyph->off_x = 0; - glyph->off_y = (float)(font_size->size * 0.85) - font_size->size; return glyph; } @@ -230,7 +243,7 @@ struct text_render_metrics { int _gfx_render_text(Texture *dst, char *msg, struct text_render_metrics *tm) { float pos_x = tm->pos.x; - float pos_y = tm->pos.y; + int pos_y = tm->pos.y - roundf(tm->size * 0.15f); struct font_size *font_size = get_font_size(tm->type, tm->size); if (FT_Set_Pixel_Sizes(font_size->font->font, 0, font_size->size)) { WARNING("Failed setting font size to %d", font_size->size); @@ -255,14 +268,14 @@ int _gfx_render_text(Texture *dst, char *msg, struct text_render_metrics *tm) // render glyph Texture *t = &glyph->t[tm->weight]; - float x_pos = pos_x + glyph->off_x; - int y_pos = roundf(pos_y + glyph->off_y); if (tm->mode == RENDER_BLENDED) { - gfx_draw_glyph(dst, x_pos, y_pos, t, tm->color, config.text_x_scale, tm->edge_width); + float x = pos_x - glyph->rect.x; + int y = pos_y - glyph->rect.y; + gfx_draw_glyph(dst, x, y, t, tm->color, config.text_x_scale, tm->edge_width); } else if (tm->mode == RENDER_PMAP) { - gfx_draw_glyph_to_pmap(dst, x_pos, y_pos, t, tm->color, config.text_x_scale); + gfx_draw_glyph_to_pmap(dst, pos_x, pos_y, t, glyph->rect, tm->color, config.text_x_scale); } else if (tm->mode == RENDER_AMAP) { - gfx_draw_glyph_to_amap(dst, x_pos, y_pos, t, config.text_x_scale); + gfx_draw_glyph_to_amap(dst, pos_x, pos_y, t, glyph->rect, config.text_x_scale); } // advance