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.
This commit is contained in:
parent
18865fd32f
commit
ce664f85b1
|
@ -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.
|
// 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) {
|
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();
|
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);
|
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.
|
// 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) {
|
// FIXME: consider using something like RenColor* instead of uint8_t * for dst.
|
||||||
const int subpixel_scale = 3;
|
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::gamma_lut<>& gamma = font_renderer->gamma();
|
||||||
agg::lcd_distribution_lut& lcd_lut = font_renderer->lcd_distribution_lut();
|
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);
|
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;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,19 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Mirrors stbtt_bakedchar.
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned short x0, y0, x1, y1;
|
unsigned short x0, y0, x1, y1;
|
||||||
float xoff, yoff, xadvance;
|
float xoff, yoff, xadvance;
|
||||||
} GlyphBitmapInfo;
|
} 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;
|
struct FontRendererImpl;
|
||||||
typedef struct FontRendererImpl FontRenderer;
|
typedef struct FontRendererImpl FontRenderer;
|
||||||
|
|
||||||
|
@ -26,6 +33,10 @@ typedef struct {
|
||||||
uint8_t r, g, b;
|
uint8_t r, g, b;
|
||||||
} FontRendererColor;
|
} FontRendererColor;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int left, top, right, bottom;
|
||||||
|
} FontRendererClipArea;
|
||||||
|
|
||||||
FontRenderer * FontRendererNew(unsigned int flags, float gamma);
|
FontRenderer * FontRendererNew(unsigned int flags, float gamma);
|
||||||
|
|
||||||
void FontRendererFree(FontRenderer *);
|
void FontRendererFree(FontRenderer *);
|
||||||
|
@ -39,17 +50,20 @@ int FontRendererBakeFontBitmap(FontRenderer *, int font_height,
|
||||||
int first_char, int num_chars, GlyphBitmapInfo *glyph_info,
|
int first_char, int num_chars, GlyphBitmapInfo *glyph_info,
|
||||||
int subpixel_scale);
|
int subpixel_scale);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// FIXME: this function needs to be updated to match BlendGammaSubpixel.
|
||||||
void FontRendererBlendGamma(FontRenderer *,
|
void FontRendererBlendGamma(FontRenderer *,
|
||||||
uint8_t *dst, int dst_stride,
|
uint8_t *dst, int dst_stride,
|
||||||
uint8_t *src, int src_stride,
|
uint8_t *src, int src_stride,
|
||||||
int region_width, int region_height,
|
int region_width, int region_height,
|
||||||
FontRendererColor color);
|
FontRendererColor color);
|
||||||
|
#endif
|
||||||
|
|
||||||
void FontRendererBlendGammaSubpixel(FontRenderer *,
|
void FontRendererBlendGammaSubpixel(FontRenderer *font_renderer,
|
||||||
uint8_t *dst, int dst_stride,
|
FontRendererClipArea *clip, int x, int y,
|
||||||
uint8_t *src, int src_stride,
|
uint8_t *dst, int dst_width,
|
||||||
int region_width, int region_height,
|
const FontRendererBitmap *glyphs_bitmap,
|
||||||
FontRendererColor color);
|
const GlyphBitmapInfo *glyph, FontRendererColor color);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,16 +12,8 @@ struct RenImage {
|
||||||
int width, height;
|
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 {
|
struct GlyphSet {
|
||||||
RenCoverageImage *coverage;
|
FontRendererBitmap *image;
|
||||||
GlyphBitmapInfo glyphs[256];
|
GlyphBitmapInfo glyphs[256];
|
||||||
};
|
};
|
||||||
typedef struct GlyphSet GlyphSet;
|
typedef struct GlyphSet GlyphSet;
|
||||||
|
@ -36,8 +28,8 @@ struct RenFont {
|
||||||
|
|
||||||
|
|
||||||
static SDL_Window *window;
|
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) {
|
static void* check_alloc(void *ptr) {
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
|
@ -108,9 +100,14 @@ RenImage* ren_new_image(int width, int height) {
|
||||||
return image;
|
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);
|
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);
|
check_alloc(image);
|
||||||
image->pixels = (void*) (image + 1);
|
image->pixels = (void*) (image + 1);
|
||||||
image->width = width;
|
image->width = width;
|
||||||
|
@ -118,14 +115,10 @@ RenCoverageImage* ren_new_coverage(int width, int height, int subpixel_scale) {
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ren_free_image(RenImage *image) {
|
void ren_free_coverage_image(FontRendererBitmap *image) {
|
||||||
free(image);
|
free(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ren_free_coverage(RenCoverageImage *coverage) {
|
|
||||||
free(coverage);
|
|
||||||
}
|
|
||||||
|
|
||||||
static GlyphSet* load_glyphset(RenFont *font, int idx) {
|
static GlyphSet* load_glyphset(RenFont *font, int idx) {
|
||||||
GlyphSet *set = check_alloc(calloc(1, sizeof(GlyphSet)));
|
GlyphSet *set = check_alloc(calloc(1, sizeof(GlyphSet)));
|
||||||
|
|
||||||
|
@ -135,17 +128,17 @@ static GlyphSet* load_glyphset(RenFont *font, int idx) {
|
||||||
int width = 128;
|
int width = 128;
|
||||||
int height = 128;
|
int height = 128;
|
||||||
retry:
|
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,
|
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);
|
idx << 8, 256, set->glyphs, subpixel_scale);
|
||||||
|
|
||||||
/* retry with a larger image buffer if the buffer wasn't large enough */
|
/* retry with a larger image buffer if the buffer wasn't large enough */
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
width *= 2;
|
width *= 2;
|
||||||
height *= 2;
|
height *= 2;
|
||||||
ren_free_coverage(set->coverage);
|
ren_free_coverage_image(set->image);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +188,7 @@ void ren_free_font(RenFont *font) {
|
||||||
for (int i = 0; i < MAX_GLYPHSET; i++) {
|
for (int i = 0; i < MAX_GLYPHSET; i++) {
|
||||||
GlyphSet *set = font->sets[i];
|
GlyphSet *set = font->sets[i];
|
||||||
if (set) {
|
if (set) {
|
||||||
ren_free_coverage(set->coverage);
|
ren_free_coverage_image(set->image);
|
||||||
free(set);
|
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) {
|
void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color) {
|
||||||
if (color.a == 0) { return; }
|
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) {
|
if (sub->width <= 0 || sub->height <= 0) {
|
||||||
return;
|
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) {
|
int ren_draw_text(RenFont *font, const char *text, int x, int y, RenColor color) {
|
||||||
RenRect rect;
|
|
||||||
const char *p = text;
|
const char *p = text;
|
||||||
unsigned codepoint;
|
unsigned codepoint;
|
||||||
|
SDL_Surface *surf = SDL_GetWindowSurface(window);
|
||||||
|
FontRendererColor color_fr = { .r = color.r, .g = color.g, .b = color.b };
|
||||||
while (*p) {
|
while (*p) {
|
||||||
p = utf8_to_codepoint(p, &codepoint);
|
p = utf8_to_codepoint(p, &codepoint);
|
||||||
GlyphSet *set = get_glyphset(font, codepoint);
|
GlyphSet *set = get_glyphset(font, codepoint);
|
||||||
GlyphBitmapInfo *g = &set->glyphs[codepoint & 0xff];
|
GlyphBitmapInfo *g = &set->glyphs[codepoint & 0xff];
|
||||||
rect.x = g->x0;
|
if (color.a != 0) {
|
||||||
rect.y = g->y0;
|
FontRendererBlendGammaSubpixel(
|
||||||
rect.width = g->x1 - g->x0;
|
font->renderer, &clip,
|
||||||
rect.height = g->y1 - g->y0;
|
x, y,
|
||||||
ren_draw_coverage_with_color(font->renderer, set->coverage, &rect, x + g->xoff, y + g->yoff, color);
|
(uint8_t *) surf->pixels, surf->w,
|
||||||
|
set->image, g, color_fr);
|
||||||
|
}
|
||||||
x += g->xadvance;
|
x += g->xadvance;
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
|
|
Loading…
Reference in New Issue