Skip to content
Permalink
Browse files

text: fix bboxes, overlay TCs; add "overlay projection" parameter

The "overlay projection" allows specifying a rectangle, in the same
coordinate system as the text position, that will be used instead of the
text's BBox to compute overlay texture coordinates. This is useful to
apply an overlay effect to variably-sized text in a consistent fashion,
without having to rely on RTT.
  • Loading branch information...
Akaricchi committed May 14, 2019
1 parent bfb3941 commit 2fec4bfe62ca44c261f65fa3d51fcf8147cf4f71
Showing with 55 additions and 25 deletions.
  1. +54 −25 src/resource/font.c
  2. +1 −0 src/resource/font.h
@@ -839,23 +839,25 @@ void text_ucs4_bbox(Font *font, const uint32_t *text, uint maxlines, BBox *bbox)
x += apply_kerning(font, prev_glyph_idx, glyph);

int g_x0 = x + glyph->metrics.bearing_x;
int g_x1 = g_x0 + glyph->metrics.width;
int g_x1 = g_x0 + imax(glyph->metrics.width, glyph->sprite.w);

bbox->x.max = max(bbox->x.max, g_x0);
bbox->x.max = max(bbox->x.max, g_x1);
bbox->x.min = min(bbox->x.min, g_x0);
bbox->x.min = min(bbox->x.min, g_x1);
bbox->x.max = imax(bbox->x.max, g_x0);
bbox->x.max = imax(bbox->x.max, g_x1);
bbox->x.min = imin(bbox->x.min, g_x0);
bbox->x.min = imin(bbox->x.min, g_x1);

int g_y0 = y - glyph->metrics.bearing_y;
int g_y1 = g_y0 + glyph->metrics.height;
int g_y1 = g_y0 + imax(glyph->metrics.height, glyph->sprite.h);

bbox->y.max = max(bbox->y.max, g_y0);
bbox->y.max = max(bbox->y.max, g_y1);
bbox->y.min = min(bbox->y.min, g_y0);
bbox->y.min = min(bbox->y.min, g_y1);
bbox->y.max = imax(bbox->y.max, g_y0);
bbox->y.max = imax(bbox->y.max, g_y1);
bbox->y.min = imin(bbox->y.min, g_y0);
bbox->y.min = imin(bbox->y.min, g_y1);

prev_glyph_idx = glyph->ft_index;

x += glyph->metrics.advance;
bbox->x.max = imax(bbox->x.max, x);
}
}

@@ -961,9 +963,16 @@ static double _text_ucs4_draw(Font *font, const uint32_t *ucs4text, const TextPa
BBox bbox;
double x = params->pos.x;
double y = params->pos.y;
double iscale = 1 / font->metrics.scale;
double scale = font->metrics.scale;
double iscale = 1 / scale;

struct {
struct { double min, max; } x, y;
double w, h;
} overlay;

text_ucs4_bbox(font, ucs4text, 0, &bbox);

sp.shader_ptr = params->shader_ptr;

if(sp.shader_ptr == NULL) {
@@ -991,37 +1000,57 @@ static double _text_ucs4_draw(Font *font, const uint32_t *ucs4text, const TextPa
r_mat_push();
r_mat_translate(x, y, 0);
r_mat_scale(iscale, iscale, 1);

double orig_x = x;
double orig_y = y;
x = y = 0;

double x_orig = x;
adjust_xpos(font, ucs4text, params->align, x_orig, &x);
adjust_xpos(font, ucs4text, params->align, 0, &x);

// bbox.y.max = imax(bbox.y.max, font->metrics.ascent);
// bbox.y.min = imin(bbox.y.min, font->metrics.descent);
if(params->overlay_projection) {
FloatRect *op = params->overlay_projection;
overlay.x.min = (op->x - orig_x) * scale;
overlay.x.max = overlay.x.min + op->w * scale;
overlay.y.min = (op->y - orig_y) * scale;
overlay.y.max = overlay.y.min + op->h * scale;
} else {
overlay.x.min = bbox.x.min + x;
overlay.x.max = bbox.x.max + x;
overlay.y.min = bbox.y.min - font->metrics.descent;
overlay.y.max = bbox.y.max - font->metrics.descent;
}

double bbox_w = bbox.x.max - bbox.x.min;
double bbox_h = bbox.y.max - bbox.y.min;
overlay.w = overlay.x.max - overlay.x.min;
overlay.h = overlay.y.max - overlay.y.min;

#ifdef TEXT_DRAW_BBOX
// TODO: align this correctly in the multi-line case
double bbox_w = bbox.x.max - bbox.x.min;
double bbox_h = bbox.y.max - bbox.y.min;
double bbox_x_mid = x + bbox.x.min + bbox_w * 0.5;
double bbox_y_mid = y + bbox.y.min - font->metrics.descent + bbox_h * 0.5;
double bbox_y_mid = y + bbox.y.min + bbox_h * 0.5 - font->metrics.descent;

#if 0 /* enable to visualize the overlay projection instead */
bbox_w = overlay.w;
bbox_h = overlay.h;
bbox_x_mid = overlay.x.min + overlay.w * 0.5;
bbox_y_mid = overlay.y.min + overlay.h * 0.5;
#endif

r_state_push();
r_shader_standard_notex();
r_mat_push();
r_mat_translate(bbox_x_mid, bbox_y_mid, 0);
r_mat_scale(bbox_w, bbox_h, 0);
r_color(color_mul(RGBA(0.5, 0.5, 0.5, 0.5), r_color_current()));
r_color(color_mul(RGBA(0.5, 0.5, 0.5, 0.5), sp.color));
r_draw_quad();
r_mat_pop();
r_state_pop();
#endif

r_mat_mode(MM_TEXTURE);
r_mat_push();
r_mat_scale(1/bbox_w, 1/bbox_h, 1.0);
r_mat_translate(-bbox.x.min - (x - x_orig), -bbox.y.min + font->metrics.descent, 0);
r_mat_scale(1/overlay.w, 1/overlay.h, 1.0);
r_mat_translate(-overlay.x.min, overlay.y.min, 0);

// FIXME: is there a better way?
float texmat_offset_sign;
@@ -1039,7 +1068,7 @@ static double _text_ucs4_draw(Font *font, const uint32_t *ucs4text, const TextPa
uint32_t uchar = *tptr++;

if(uchar == '\n') {
adjust_xpos(font, tptr, params->align, x_orig, &x);
adjust_xpos(font, tptr, params->align, 0, &x);
y += font->metrics.lineskip;
continue;
}
@@ -1067,7 +1096,7 @@ static double _text_ucs4_draw(Font *font, const uint32_t *ucs4text, const TextPa
sp.scale.both = font->metrics.scale;

r_mat_push();
r_mat_translate(sp.pos.x - x_orig, sp.pos.y * texmat_offset_sign, 0);
r_mat_translate(sp.pos.x, sp.pos.y * texmat_offset_sign + overlay.h, 0);
r_mat_scale(w_saved, h_saved, 1.0);
r_mat_translate(-0.5, -0.5, 0);

@@ -1093,7 +1122,7 @@ static double _text_ucs4_draw(Font *font, const uint32_t *ucs4text, const TextPa
r_mat_pop();
r_mat_mode(mm_prev);

return x_orig + (x - x_orig) / font->metrics.scale;
return x * iscale;
}

static double _text_draw(Font *font, const char *text, const TextParams *params) {
@@ -70,6 +70,7 @@ typedef struct TextParams {
const ShaderCustomParams *shader_params;
Texture *aux_textures[R_NUM_SPRITE_AUX_TEXTURES];
double max_width;
FloatRect *overlay_projection;
BlendMode blend;
Alignment align;
} TextParams;

0 comments on commit 2fec4bf

Please sign in to comment.
You can’t perform that action at this time.