From ce664f85b1070cade57fbf0b7c694a6b628f11ce Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Thu, 11 Jun 2020 16:39:11 +0200 Subject: [PATCH] Move rendering buffers pointers computations inside FontRendererBlendGammaSubpixel The logic is to disentangle the code between renderer.c and FontRenderer so that this latter has a simple, logical interface. --- lib/font_renderer/font_renderer.cpp | 38 ++++++++++-- lib/font_renderer/font_renderer.h | 26 ++++++-- src/renderer.c | 92 +++++++++-------------------- 3 files changed, 82 insertions(+), 74 deletions(-) diff --git a/lib/font_renderer/font_renderer.cpp b/lib/font_renderer/font_renderer.cpp index 4e954283..efa3483c 100644 --- a/lib/font_renderer/font_renderer.cpp +++ b/lib/font_renderer/font_renderer.cpp @@ -277,6 +277,7 @@ void blend_solid_hspan_rgb_subpixel(agg::rendering_buffer& rbuf, agg::gamma_lut< } } +#if 0 // destination implicitly BGRA32. Source implictly single-byte renderer_alpha coverage. void FontRendererBlendGamma(FontRenderer *font_renderer, uint8_t *dst, int dst_stride, uint8_t *src, int src_stride, int region_width, int region_height, FontRendererColor color) { blender_gamma_type& blender = font_renderer->blender(); @@ -287,16 +288,43 @@ void FontRendererBlendGamma(FontRenderer *font_renderer, uint8_t *dst, int dst_s blend_solid_hspan(dst_ren_buf, blender, x, y, region_width, color_a, covers); } } +#endif // destination implicitly BGRA32. Source implictly single-byte renderer_alpha coverage with subpixel scale = 3. -void FontRendererBlendGammaSubpixel(FontRenderer *font_renderer, uint8_t *dst, int dst_stride, uint8_t *src, int src_stride, int region_width, int region_height, FontRendererColor color) { - const int subpixel_scale = 3; +// FIXME: consider using something like RenColor* instead of uint8_t * for dst. +void FontRendererBlendGammaSubpixel(FontRenderer *font_renderer, FontRendererClipArea *clip, int x, int y, uint8_t *dst, int dst_width, const FontRendererBitmap *glyphs_bitmap, const GlyphBitmapInfo *glyph, FontRendererColor color) { agg::gamma_lut<>& gamma = font_renderer->gamma(); agg::lcd_distribution_lut& lcd_lut = font_renderer->lcd_distribution_lut(); - agg::rendering_buffer dst_ren_buf(dst, region_width, region_height, dst_stride); + const int subpixel_scale = 3; + const int pixel_size = 4; // Pixel size for BGRA32 format. + + x += glyph->xoff; + y += glyph->yoff; + + int glyph_x = glyph->x0, glyph_y = glyph->y0; + int glyph_width = glyph->x1 - glyph->x0; + int glyph_height = glyph->y1 - glyph->y0; + + int n; + if ((n = clip->left - x) > 0) { glyph_width -= n; glyph_x += n; x += n; } + if ((n = clip->top - y) > 0) { glyph_height -= n; glyph_y += n; y += n; } + if ((n = x + glyph_width - clip->right ) > 0) { glyph_width -= n; } + if ((n = y + glyph_height - clip->bottom) > 0) { glyph_height -= n; } + + if (glyph_width <= 0 || glyph_height <= 0) { + return; + } + + dst += (x + y * dst_width) * pixel_size; + agg::rendering_buffer dst_ren_buf(dst, glyph_width, glyph_height, dst_width * pixel_size); + + uint8_t *src = glyphs_bitmap->pixels + (glyph_x + glyph_y * glyphs_bitmap->width) * subpixel_scale; + int src_stride = glyphs_bitmap->width * subpixel_scale; + const agg::rgba8 color_a(color.r, color.g, color.b); - for (int x = 0, y = 0; y < region_height; y++) { + for (int x = 0, y = 0; y < glyph_height; y++) { agg::int8u *covers = src + y * src_stride; - blend_solid_hspan_rgb_subpixel(dst_ren_buf, gamma, lcd_lut, x, y, region_width * subpixel_scale, color_a, covers); + blend_solid_hspan_rgb_subpixel(dst_ren_buf, gamma, lcd_lut, x, y, glyph_width * subpixel_scale, color_a, covers); } } + diff --git a/lib/font_renderer/font_renderer.h b/lib/font_renderer/font_renderer.h index 0d03bad9..d60ad0aa 100644 --- a/lib/font_renderer/font_renderer.h +++ b/lib/font_renderer/font_renderer.h @@ -7,12 +7,19 @@ extern "C" { #endif -// Mirrors stbtt_bakedchar. typedef struct { unsigned short x0, y0, x1, y1; float xoff, yoff, xadvance; } GlyphBitmapInfo; +// Important: when a subpixel scale is used the width below will be the width in logical pixel. +// As each logical pixel contains 3 subpixels it means that the 'pixels' pointer +// will hold enough space for '3 * width' uint8_t values. +typedef struct { + uint8_t *pixels; + int width, height; +} FontRendererBitmap; + struct FontRendererImpl; typedef struct FontRendererImpl FontRenderer; @@ -26,6 +33,10 @@ typedef struct { uint8_t r, g, b; } FontRendererColor; +typedef struct { + int left, top, right, bottom; +} FontRendererClipArea; + FontRenderer * FontRendererNew(unsigned int flags, float gamma); void FontRendererFree(FontRenderer *); @@ -39,17 +50,20 @@ int FontRendererBakeFontBitmap(FontRenderer *, int font_height, int first_char, int num_chars, GlyphBitmapInfo *glyph_info, int subpixel_scale); +#if 0 +// FIXME: this function needs to be updated to match BlendGammaSubpixel. void FontRendererBlendGamma(FontRenderer *, uint8_t *dst, int dst_stride, uint8_t *src, int src_stride, int region_width, int region_height, FontRendererColor color); +#endif -void FontRendererBlendGammaSubpixel(FontRenderer *, - uint8_t *dst, int dst_stride, - uint8_t *src, int src_stride, - int region_width, int region_height, - FontRendererColor color); +void FontRendererBlendGammaSubpixel(FontRenderer *font_renderer, + FontRendererClipArea *clip, int x, int y, + uint8_t *dst, int dst_width, + const FontRendererBitmap *glyphs_bitmap, + const GlyphBitmapInfo *glyph, FontRendererColor color); #ifdef __cplusplus } diff --git a/src/renderer.c b/src/renderer.c index 451edeef..e43337db 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -12,16 +12,8 @@ struct RenImage { int width, height; }; -// Important: when a subpixel scale is used the width below will be the width in logical pixel. -// As each logical pixel contains 3 subpixels it means that the 'pixels' pointer -// will hold enough space for '3 * width' uint8_t values. -typedef struct { - uint8_t *pixels; - int width, height; -} RenCoverageImage; - struct GlyphSet { - RenCoverageImage *coverage; + FontRendererBitmap *image; GlyphBitmapInfo glyphs[256]; }; typedef struct GlyphSet GlyphSet; @@ -36,8 +28,8 @@ struct RenFont { static SDL_Window *window; -static struct { int left, top, right, bottom; } clip; - +//static struct { int left, top, right, bottom; } clip; +static FontRendererClipArea clip; static void* check_alloc(void *ptr) { if (!ptr) { @@ -108,9 +100,14 @@ RenImage* ren_new_image(int width, int height) { return image; } -RenCoverageImage* ren_new_coverage(int width, int height, int subpixel_scale) { +void ren_free_image(RenImage *image) { + free(image); +} + +// FIXME: move this function into FontRenderer and change name. +FontRendererBitmap* ren_new_coverage_image(int width, int height, int subpixel_scale) { assert(width > 0 && height > 0); - RenCoverageImage *image = malloc(sizeof(RenCoverageImage) + width * height * subpixel_scale * sizeof(uint8_t)); + FontRendererBitmap *image = malloc(sizeof(FontRendererBitmap) + width * height * subpixel_scale * sizeof(uint8_t)); check_alloc(image); image->pixels = (void*) (image + 1); image->width = width; @@ -118,14 +115,10 @@ RenCoverageImage* ren_new_coverage(int width, int height, int subpixel_scale) { return image; } -void ren_free_image(RenImage *image) { +void ren_free_coverage_image(FontRendererBitmap *image) { free(image); } -void ren_free_coverage(RenCoverageImage *coverage) { - free(coverage); -} - static GlyphSet* load_glyphset(RenFont *font, int idx) { GlyphSet *set = check_alloc(calloc(1, sizeof(GlyphSet))); @@ -135,17 +128,17 @@ static GlyphSet* load_glyphset(RenFont *font, int idx) { int width = 128; int height = 128; retry: - set->coverage = ren_new_coverage(width, height, subpixel_scale); + set->image = ren_new_coverage_image(width, height, subpixel_scale); int res = FontRendererBakeFontBitmap(font->renderer, font->height, - (void *) set->coverage->pixels, width, height, + (void *) set->image->pixels, width, height, idx << 8, 256, set->glyphs, subpixel_scale); /* retry with a larger image buffer if the buffer wasn't large enough */ if (res < 0) { width *= 2; height *= 2; - ren_free_coverage(set->coverage); + ren_free_coverage_image(set->image); goto retry; } @@ -195,7 +188,7 @@ void ren_free_font(RenFont *font) { for (int i = 0; i < MAX_GLYPHSET; i++) { GlyphSet *set = font->sets[i]; if (set) { - ren_free_coverage(set->coverage); + ren_free_coverage_image(set->image); free(set); } } @@ -279,19 +272,14 @@ void ren_draw_rect(RenRect rect, RenColor color) { } } -static void clip_point_inside_rect(int *x, int *y, RenRect *sub) { - /* clip */ - int n; - if ((n = clip.left - (*x)) > 0) { sub->width -= n; sub->x += n; (*x) += n; } - if ((n = clip.top - (*y)) > 0) { sub->height -= n; sub->y += n; (*y) += n; } - if ((n = (*x) + sub->width - clip.right ) > 0) { sub->width -= n; } - if ((n = (*y) + sub->height - clip.bottom) > 0) { sub->height -= n; } -} - void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color) { if (color.a == 0) { return; } - clip_point_inside_rect(&x, &y, sub); + int n; + if ((n = clip.left - x) > 0) { sub->width -= n; sub->x += n; x += n; } + if ((n = clip.top - y) > 0) { sub->height -= n; sub->y += n; x += n; } + if ((n = x + sub->width - clip.right ) > 0) { sub->width -= n; } + if ((n = y + sub->height - clip.bottom) > 0) { sub->height -= n; } if (sub->width <= 0 || sub->height <= 0) { return; @@ -317,44 +305,22 @@ void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color) } } -static void ren_draw_coverage_with_color(FontRenderer *renderer, RenCoverageImage *image, RenRect *sub, int x, int y, RenColor color) { - if (color.a == 0) { return; } - - clip_point_inside_rect(&x, &y, sub); - - if (sub->width <= 0 || sub->height <= 0) { - return; - } - - /* draw */ - SDL_Surface *surf = SDL_GetWindowSurface(window); - const int subpixel_scale = 3; - uint8_t *s = image->pixels; - RenColor *d = (RenColor*) surf->pixels; - s += (sub->x + sub->y * image->width) * subpixel_scale; - d += x + y * surf->w; - const int surf_pixel_size = 4; - FontRendererBlendGammaSubpixel( - renderer, - (uint8_t *) d, surf->w * surf_pixel_size, - s, image->width * subpixel_scale, - sub->width, sub->height, - (FontRendererColor) { .r = color.r, .g = color.g, .b = color.b }); -} - int ren_draw_text(RenFont *font, const char *text, int x, int y, RenColor color) { - RenRect rect; const char *p = text; unsigned codepoint; + SDL_Surface *surf = SDL_GetWindowSurface(window); + FontRendererColor color_fr = { .r = color.r, .g = color.g, .b = color.b }; while (*p) { p = utf8_to_codepoint(p, &codepoint); GlyphSet *set = get_glyphset(font, codepoint); GlyphBitmapInfo *g = &set->glyphs[codepoint & 0xff]; - rect.x = g->x0; - rect.y = g->y0; - rect.width = g->x1 - g->x0; - rect.height = g->y1 - g->y0; - ren_draw_coverage_with_color(font->renderer, set->coverage, &rect, x + g->xoff, y + g->yoff, color); + if (color.a != 0) { + FontRendererBlendGammaSubpixel( + font->renderer, &clip, + x, y, + (uint8_t *) surf->pixels, surf->w, + set->image, g, color_fr); + } x += g->xadvance; } return x;