From 93a36617f99e59ed46fbb0ffab9446ed565d1888 Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Thu, 11 Jun 2020 23:11:40 +0200 Subject: [PATCH] Bring back simple grayscale rendering option --- lib/font_renderer/font_renderer.cpp | 141 ++++++++++++---------------- lib/font_renderer/font_renderer.h | 28 ++---- src/renderer.c | 11 +-- 3 files changed, 70 insertions(+), 110 deletions(-) diff --git a/lib/font_renderer/font_renderer.cpp b/lib/font_renderer/font_renderer.cpp index f97fede8..205f3756 100644 --- a/lib/font_renderer/font_renderer.cpp +++ b/lib/font_renderer/font_renderer.cpp @@ -15,9 +15,39 @@ struct FR_Bitmap { int width, height; }; -typedef agg::blender_rgb_gamma > blender_gamma_type; +class FR_Impl { +public: + // Conventional LUT values: (1./3., 2./9., 1./9.) + // The values below are fine tuned as in the Elementary Plot library. -FR_Bitmap* FR_Bitmap_New(int width, int height, int subpixel_scale) { + FR_Impl(bool hinting, bool kerning, bool subpixel, float gamma_value) : + m_renderer(hinting, kerning, subpixel), + m_gamma_lut(double(gamma_value)), + m_lcd_lut(0.448, 0.184, 0.092), + m_subpixel(subpixel) + { } + + font_renderer_alpha& renderer_alpha() { return m_renderer; } + agg::gamma_lut<>& gamma() { return m_gamma_lut; } + agg::lcd_distribution_lut& lcd_distribution_lut() { return m_lcd_lut; } + int subpixel_scale() const { return (m_subpixel ? 3 : 1); } + +private: + font_renderer_alpha m_renderer; + agg::gamma_lut<> m_gamma_lut; + agg::lcd_distribution_lut m_lcd_lut; + int m_subpixel; +}; + +FontRenderer *FR_New(unsigned int flags, float gamma) { + bool hinting = ((flags & FR_HINTING) != 0); + bool kerning = ((flags & FR_KERNING) != 0); + bool subpixel = ((flags & FR_SUBPIXEL) != 0); + return new FR_Impl(hinting, kerning, subpixel, gamma); +} + +FR_Bitmap* FR_Bitmap_New(FontRenderer *font_renderer, int width, int height) { + const int subpixel_scale = font_renderer->subpixel_scale(); FR_Bitmap *image = (FR_Bitmap *) malloc(sizeof(FR_Bitmap) + width * height * subpixel_scale); if (!image) { return NULL; } image->pixels = (agg::int8u *) (image + 1); @@ -30,39 +60,6 @@ void FR_Bitmap_Free(FR_Bitmap *image) { free(image); } -class FR_Impl { -public: - // Conventional LUT values: (1./3., 2./9., 1./9.) - // The values below are fine tuned as in the Elementary Plot library. - - FR_Impl(bool hinting, bool kerning, bool subpixel, float gamma_value) : - m_renderer(hinting, kerning, subpixel), - m_gamma_lut(double(gamma_value)), - m_blender(), - m_lcd_lut(0.448, 0.184, 0.092) - { - m_blender.gamma(m_gamma_lut); - } - - font_renderer_alpha& renderer_alpha() { return m_renderer; } - blender_gamma_type& blender() { return m_blender; } - agg::gamma_lut<>& gamma() { return m_gamma_lut; } - agg::lcd_distribution_lut& lcd_distribution_lut() { return m_lcd_lut; } - -private: - font_renderer_alpha m_renderer; - agg::gamma_lut<> m_gamma_lut; - blender_gamma_type m_blender; - agg::lcd_distribution_lut m_lcd_lut; -}; - -FontRenderer *FR_New(unsigned int flags, float gamma) { - bool hinting = ((flags & FONT_RENDERER_HINTING) != 0); - bool kerning = ((flags & FONT_RENDERER_KERNING) != 0); - bool subpixel = ((flags & FONT_RENDERER_SUBPIXEL) != 0); - return new FR_Impl(hinting, kerning, subpixel, gamma); -} - void FR_Free(FontRenderer *font_renderer) { delete font_renderer; } @@ -171,9 +168,11 @@ static int ceil_to_multiple(int n, int p) { int FR_Bake_Font_Bitmap(FontRenderer *font_renderer, int font_height, FR_Bitmap *image, - int first_char, int num_chars, FR_Bitmap_Glyph_Metrics *glyphs, int subpixel_scale) + int first_char, int num_chars, FR_Bitmap_Glyph_Metrics *glyphs) { font_renderer_alpha& renderer_alpha = font_renderer->renderer_alpha(); + agg::lcd_distribution_lut& lcd_lut = font_renderer->lcd_distribution_lut(); + const int subpixel_scale = font_renderer->subpixel_scale(); agg::int8u *pixels = image->pixels; const int pixels_width = image->width, pixels_height = image->height; @@ -190,7 +189,6 @@ int FR_Bake_Font_Bitmap(FontRenderer *font_renderer, int font_height, const int pad_y = font_height / 10; const int y_step = font_height + 2 * pad_y; - agg::lcd_distribution_lut& lcd_lut = font_renderer->lcd_distribution_lut(); agg::rendering_buffer ren_buf(pixels, pixels_width * subpixel_scale, pixels_height, -pixels_width * subpixel_scale * pixel_size); // When using subpixel font rendering it is needed to leave a padding pixel on the left and on the right. // Since each pixel is composed by n subpixel we set below x_start to subpixel_scale instead than zero. @@ -232,7 +230,7 @@ int FR_Bake_Font_Bitmap(FontRenderer *font_renderer, int font_height, glyph_info.yoff = -pad_y; glyph_info.xadvance = (x_next - x) / subpixel_scale; - if (glyph_info.x1 > glyph_info.x0) { + if (subpixel_scale != 1 && glyph_info.x1 > glyph_info.x0) { glyph_lut_convolution(ren_buf, lcd_lut, cover_swap_buffer, glyph_info); } glyph_trim_rect(ren_buf, glyph_info, subpixel_scale); @@ -244,39 +242,29 @@ int FR_Bake_Font_Bitmap(FontRenderer *font_renderer, int font_height, return res; } -void blend_solid_hspan(agg::rendering_buffer& rbuf, blender_gamma_type& blender, +template +void blend_solid_hspan(agg::rendering_buffer& rbuf, agg::gamma_lut<>& gamma, int x, int y, unsigned len, const agg::rgba8& c, const agg::int8u* covers) { - typedef typename blender_gamma_type::color_type color_type; - typedef typename blender_gamma_type::order_type order_type; - typedef typename color_type::value_type value_type; - typedef typename color_type::calc_type calc_type; - - if (c.a) + const int pixel_size = 4; + agg::int8u* p = rbuf.row_ptr(y) + x * pixel_size; + do { - value_type* p = (value_type*)rbuf.row_ptr(x, y, len) + (x << 2); - do - { - calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; - if(alpha == color_type::base_mask) - { - p[order_type::R] = c.r; - p[order_type::G] = c.g; - p[order_type::B] = c.b; - } - else - { - blender.blend_pix(p, c.r, c.g, c.b, alpha, *covers); - } - p += 4; - ++covers; - } - while(--len); + const unsigned alpha = *covers; + const unsigned r = gamma.dir(p[Order::R]), g = gamma.dir(p[Order::G]), b = gamma.dir(p[Order::B]); + p[Order::R] = gamma.inv((((gamma.dir(c.r) - r) * alpha) >> 8) + r); + p[Order::G] = gamma.inv((((gamma.dir(c.g) - g) * alpha) >> 8) + g); + p[Order::B] = gamma.inv((((gamma.dir(c.b) - b) * alpha) >> 8) + b); + // Leave p[3], the alpha channel value unmodified. + p += 4; + ++covers; } + while(--len); } -void blend_solid_hspan_rgb_subpixel(agg::rendering_buffer& rbuf, agg::gamma_lut<>& gamma, agg::lcd_distribution_lut& lcd_lut, +template +void blend_solid_hspan_subpixel(agg::rendering_buffer& rbuf, agg::gamma_lut<>& gamma, agg::lcd_distribution_lut& lcd_lut, const int x, const int y, unsigned len, const agg::rgba8& c, const agg::int8u* covers) @@ -286,7 +274,7 @@ void blend_solid_hspan_rgb_subpixel(agg::rendering_buffer& rbuf, agg::gamma_lut< agg::int8u* p = rbuf.row_ptr(y) + x * pixel_size; // Indexes to adress RGB colors in a BGRA32 format. - const int pixel_index[3] = {2, 1, 0}; + const int pixel_index[3] = {Order::R, Order::G, Order::B}; for (unsigned cx = 0; cx < len; cx += 3) { for (int i = 0; i < 3; i++) { @@ -301,25 +289,12 @@ 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 FR_Blend_Gamma(FontRenderer *font_renderer, uint8_t *dst, int dst_stride, uint8_t *src, int src_stride, int region_width, int region_height, FR_Color color) { - blender_gamma_type& blender = font_renderer->blender(); - agg::rendering_buffer dst_ren_buf(dst, region_width, region_height, dst_stride); - const agg::rgba8 color_a(color.r, color.g, color.b); - for (int x = 0, y = 0; y < region_height; y++) { - agg::int8u *covers = src + y * src_stride; - 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. // FIXME: consider using something like RenColor* instead of uint8_t * for dst. -void FR_Blend_Gamma_Subpixel(FontRenderer *font_renderer, FR_Clip_Area *clip, int x, int y, uint8_t *dst, int dst_width, const FR_Bitmap *glyphs_bitmap, const FR_Bitmap_Glyph_Metrics *glyph, FR_Color color) { +void FR_Blend_Glyph(FontRenderer *font_renderer, FR_Clip_Area *clip, int x, int y, uint8_t *dst, int dst_width, const FR_Bitmap *glyphs_bitmap, const FR_Bitmap_Glyph_Metrics *glyph, FR_Color color) { agg::gamma_lut<>& gamma = font_renderer->gamma(); agg::lcd_distribution_lut& lcd_lut = font_renderer->lcd_distribution_lut(); - const int subpixel_scale = 3; + const int subpixel_scale = font_renderer->subpixel_scale(); const int pixel_size = 4; // Pixel size for BGRA32 format. x += glyph->xoff; @@ -348,7 +323,11 @@ void FR_Blend_Gamma_Subpixel(FontRenderer *font_renderer, FR_Clip_Area *clip, in const agg::rgba8 color_a(color.r, color.g, color.b); 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, glyph_width * subpixel_scale, color_a, covers); + if (subpixel_scale == 1) { + blend_solid_hspan(dst_ren_buf, gamma, x, y, glyph_width, color_a, covers); + } else { + blend_solid_hspan_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 afd71bff..96d023d0 100644 --- a/lib/font_renderer/font_renderer.h +++ b/lib/font_renderer/font_renderer.h @@ -18,9 +18,9 @@ struct FR_Impl; typedef struct FR_Impl FontRenderer; enum { - FONT_RENDERER_HINTING = 1 << 0, - FONT_RENDERER_KERNING = 1 << 1, - FONT_RENDERER_SUBPIXEL = 1 << 2, + FR_HINTING = 1 << 0, + FR_KERNING = 1 << 2, + FR_SUBPIXEL = 1 << 3, }; typedef struct { @@ -32,35 +32,19 @@ typedef struct { } FR_Clip_Area; FontRenderer * FR_New(unsigned int flags, float gamma); - void FR_Free(FontRenderer *); - +FR_Bitmap* FR_Bitmap_New(FontRenderer *, int width, int height); int FR_Load_Font(FontRenderer *, const char *filename); - int FR_Get_Font_Height(FontRenderer *, float size); - int FR_Bake_Font_Bitmap(FontRenderer *, int font_height, FR_Bitmap *image, - int first_char, int num_chars, FR_Bitmap_Glyph_Metrics *glyph_info, - int subpixel_scale); - -#if 0 -// FIXME: this function needs to be updated to match BlendGammaSubpixel. -void FR_Blend_Gamma(FontRenderer *, - uint8_t *dst, int dst_stride, - uint8_t *src, int src_stride, - int region_width, int region_height, - FR_Color color); -#endif - -void FR_Blend_Gamma_Subpixel(FontRenderer *font_renderer, + int first_char, int num_chars, FR_Bitmap_Glyph_Metrics *glyph_info); +void FR_Blend_Glyph(FontRenderer *font_renderer, FR_Clip_Area *clip, int x, int y, uint8_t *dst, int dst_width, const FR_Bitmap *glyphs_bitmap, const FR_Bitmap_Glyph_Metrics *glyph, FR_Color color); -FR_Bitmap* FR_Bitmap_New(int width, int height, int subpixel_scale); - void FR_Bitmap_Free(FR_Bitmap *image); #ifdef __cplusplus diff --git a/src/renderer.c b/src/renderer.c index bbdfa2b4..a99ba0a9 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -28,7 +28,6 @@ struct RenFont { static SDL_Window *window; -//static struct { int left, top, right, bottom; } clip; static FR_Clip_Area clip; static void* check_alloc(void *ptr) { @@ -107,16 +106,14 @@ void ren_free_image(RenImage *image) { static GlyphSet* load_glyphset(RenFont *font, int idx) { GlyphSet *set = check_alloc(calloc(1, sizeof(GlyphSet))); - const int subpixel_scale = 3; - /* init image */ int width = 128; int height = 128; retry: - set->image = check_alloc(FR_Bitmap_New(width, height, subpixel_scale)); + set->image = check_alloc(FR_Bitmap_New(font->renderer, width, height)); int res = FR_Bake_Font_Bitmap(font->renderer, font->height, - set->image, idx << 8, 256, set->glyphs, subpixel_scale); + set->image, idx << 8, 256, set->glyphs); /* retry with a larger image buffer if the buffer wasn't large enough */ if (res < 0) { @@ -152,7 +149,7 @@ RenFont* ren_load_font(const char *filename, float size) { font->size = size; const float gamma = 1.5; - font->renderer = FR_New(FONT_RENDERER_HINTING|FONT_RENDERER_SUBPIXEL, gamma); + font->renderer = FR_New(FR_HINTING | FR_SUBPIXEL, gamma); if (FR_Load_Font(font->renderer, filename)) { free(font); return NULL; @@ -299,7 +296,7 @@ int ren_draw_text(RenFont *font, const char *text, int x, int y, RenColor color) GlyphSet *set = get_glyphset(font, codepoint); FR_Bitmap_Glyph_Metrics *g = &set->glyphs[codepoint & 0xff]; if (color.a != 0) { - FR_Blend_Gamma_Subpixel(font->renderer, &clip, + FR_Blend_Glyph(font->renderer, &clip, x, y, (uint8_t *) surf->pixels, surf->w, set->image, g, color_fr); } x += g->xadvance;