Index: rnd_inclib/font/font.c =================================================================== --- rnd_inclib/font/font.c (revision 36513) +++ rnd_inclib/font/font.c (revision 36514) @@ -1,10 +1,90 @@ #include #include +#include #include #include #define MAX_SIMPLE_POLY_POINTS 256 +/* Very rough estimation on the full width of the text */ +rnd_coord_t rnd_font_string_width(rnd_font_t *font, double scx, const unsigned char *string) +{ + rnd_coord_t w = 0; + const rnd_box_t *unk_gl; + + if (string == NULL) + return 0; + + unk_gl = &font->unknown_glyph; + + for(; *string != '\0'; string++) { + if ((*string <= RND_FONT_MAX_GLYPHS) && font->glyph[*string].valid) + w += (font->glyph[*string].width + font->glyph[*string].xdelta); + else + w += (unk_gl->X2 - unk_gl->X1) * 6 / 5; + } + return rnd_round((double)w * scx); +} + +rnd_coord_t rnd_font_string_height(rnd_font_t *font, double scy, const unsigned char *string) +{ + rnd_coord_t h; + + if (string == NULL) + return 0; + + h = font->max_height; + + for(; *string != '\0'; string++) + if (*string == '\n') + h += font->max_height; + + return rnd_round((double)h * scy); +} + +RND_INLINE void cheap_text_line(rnd_xform_mx_t mx, rnd_coord_t x1, rnd_coord_t y1, rnd_coord_t x2, rnd_coord_t y2, rnd_font_draw_atom_cb cb, void *cb_ctx) +{ + rnd_glyph_atom_t a; + + a.type = RND_GLYPH_LINE; + a.line.x1 = rnd_round(rnd_xform_x(mx, x1, y1)); + a.line.y1 = rnd_round(rnd_xform_y(mx, x1, y1)); + a.line.x2 = rnd_round(rnd_xform_x(mx, x2, y2)); + a.line.y2 = rnd_round(rnd_xform_y(mx, x2, y2)); + a.line.thickness = -1; + + cb(cb_ctx, &a); +} + +/* Decreased level-of-detail: draw only a few lines for the whole text */ +RND_INLINE int draw_text_cheap(rnd_font_t *font, rnd_xform_mx_t mx, const unsigned char *string, double scx, double scy, rnd_font_tiny_t tiny, rnd_font_draw_atom_cb cb, void *cb_ctx) +{ + rnd_coord_t w, h = rnd_font_string_height(font, scy, string); + + if (tiny == RND_FONT_TINY_HIDE) { + if (h <= rnd_render->coord_per_pix*6) /* <= 6 pixel high: unreadable */ + return 1; + } + else if (tiny == RND_FONT_TINY_CHEAP) { + if (h <= rnd_render->coord_per_pix*2) { /* <= 1 pixel high: draw a single line in the middle */ + w = rnd_font_string_width(font, scx, string); + cheap_text_line(mx, 0, h/2, w, h/2, cb, cb_ctx); + return 1; + } + else if (h <= rnd_render->coord_per_pix*4) { /* <= 4 pixel high: draw a mirrored Z-shape */ + w = rnd_font_string_width(font, scx, string); + h /= 4; + cheap_text_line(mx, 0, h, w, h, cb, cb_ctx); + cheap_text_line(mx, 0, h, w, h*3, cb, cb_ctx); + cheap_text_line(mx, 0, h*3, w, h*3, cb, cb_ctx); + return 1; + } + } + + return 0; +} + + RND_INLINE void draw_atom(const rnd_glyph_atom_t *a, rnd_xform_mx_t mx, rnd_coord_t dx, double scx, double scy, double rotdeg, rnd_font_mirror_t mirror, rnd_coord_t thickness, rnd_coord_t min_line_width, int poly_thin, rnd_font_draw_atom_cb cb, void *cb_ctx) { long nx, ny, h; @@ -83,7 +163,7 @@ cb(cb_ctx, &res); } -RND_FONT_DRAW_API void rnd_font_draw_string(rnd_font_t *font, const unsigned char *string, rnd_coord_t x0, rnd_coord_t y0, double scx, double scy, double rotdeg, rnd_font_mirror_t mirror, rnd_coord_t thickness, rnd_coord_t min_line_width, int poly_thin, rnd_font_draw_atom_cb cb, void *cb_ctx) +RND_FONT_DRAW_API void rnd_font_draw_string(rnd_font_t *font, const unsigned char *string, rnd_coord_t x0, rnd_coord_t y0, double scx, double scy, double rotdeg, rnd_font_mirror_t mirror, rnd_coord_t thickness, rnd_coord_t min_line_width, int poly_thin, rnd_font_tiny_t tiny, rnd_font_draw_atom_cb cb, void *cb_ctx) { rnd_xform_mx_t mx = RND_XFORM_MX_IDENT; const unsigned char *s; @@ -95,6 +175,12 @@ rnd_xform_mx_rotate(mx, rotdeg); rnd_xform_mx_scale(mx, scx, scy); + /* Text too small at this zoom level: cheap draw */ + if (tiny != RND_FONT_TINY_ACCURATE) { + if (draw_text_cheap(font, mx, string, scx, scy, tiny, cb, cb_ctx)) + return; + } + for(s = string; *s != '\0'; s++) { /* draw atoms if symbol is valid and data is present */ if ((*s <= RND_FONT_MAX_GLYPHS) && font->glyph[*s].valid) { Index: rnd_inclib/font/font.h =================================================================== --- rnd_inclib/font/font.h (revision 36513) +++ rnd_inclib/font/font.h (revision 36514) @@ -56,6 +56,12 @@ RND_TXT_MIRROR_X = 2 /* change X coords (mirror over the Y axis) */ } rnd_font_mirror_t; +typedef enum rnd_font_tiny_e { /* How to draw text that is too tiny to be readable */ + RND_FONT_TINY_HIDE, /* do not draw it at all */ + RND_FONT_TINY_CHEAP, /* draw a cheaper, simplified approximation that shows there's something there */ + RND_FONT_TINY_ACCURATE /* always draw text accurately, even if it will end up unreadable */ +} rnd_font_tiny_t; + void rnd_font_set_info(rnd_font_t *dst); rnd_glyph_line_t *rnd_font_new_line_in_glyph(rnd_glyph_t *glyph, rnd_coord_t x1, rnd_coord_t y1, rnd_coord_t x2, rnd_coord_t y2, rnd_coord_t thickness); @@ -72,7 +78,7 @@ typedef void (*rnd_font_draw_atom_cb)(void *cb_ctx, const rnd_glyph_atom_t *a); -RND_FONT_DRAW_API void rnd_font_draw_string(rnd_font_t *font, const unsigned char *string, rnd_coord_t x0, rnd_coord_t y0, double scx, double scy, double rotdeg, rnd_font_mirror_t mirror, rnd_coord_t thickness, rnd_coord_t min_line_width, int poly_thin, rnd_font_draw_atom_cb cb, void *cb_ctx); +RND_FONT_DRAW_API void rnd_font_draw_string(rnd_font_t *font, const unsigned char *string, rnd_coord_t x0, rnd_coord_t y0, double scx, double scy, double rotdeg, rnd_font_mirror_t mirror, rnd_coord_t thickness, rnd_coord_t min_line_width, int poly_thin, rnd_font_tiny_t tiny, rnd_font_draw_atom_cb cb, void *cb_ctx); #endif