mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-23 07:59:42 +00:00
(freetype/stb_unicode/bitmapfont) Prevent texture bleed when rendering text at non-integer scales
This commit is contained in:
parent
b69e023736
commit
fc05c0805b
@ -28,6 +28,11 @@
|
||||
#define BMP_ATLAS_ROWS 16
|
||||
#define BMP_ATLAS_SIZE (BMP_ATLAS_COLS * BMP_ATLAS_ROWS)
|
||||
|
||||
/* Padding is required between each glyph in
|
||||
* the atlas to prevent texture bleed when
|
||||
* drawing with linear filtering enabled */
|
||||
#define BMP_ATLAS_PADDING 1
|
||||
|
||||
typedef struct bm_renderer
|
||||
{
|
||||
unsigned scale_factor;
|
||||
@ -96,16 +101,16 @@ static void *font_renderer_bmp_init(const char *font_path, float font_size)
|
||||
if (!handle->scale_factor)
|
||||
handle->scale_factor = 1;
|
||||
|
||||
handle->atlas.width = FONT_WIDTH * handle->scale_factor * BMP_ATLAS_COLS;
|
||||
handle->atlas.height = FONT_HEIGHT * handle->scale_factor * BMP_ATLAS_ROWS;
|
||||
handle->atlas.width = (BMP_ATLAS_PADDING + (FONT_WIDTH * handle->scale_factor)) * BMP_ATLAS_COLS;
|
||||
handle->atlas.height = (BMP_ATLAS_PADDING + (FONT_HEIGHT * handle->scale_factor)) * BMP_ATLAS_ROWS;
|
||||
handle->atlas.buffer = (uint8_t*)calloc(handle->atlas.width * handle->atlas.height, 1);
|
||||
|
||||
for (i = 0; i < BMP_ATLAS_SIZE; i++)
|
||||
{
|
||||
unsigned x = (i % BMP_ATLAS_COLS) *
|
||||
handle->scale_factor * FONT_WIDTH;
|
||||
(BMP_ATLAS_PADDING + (handle->scale_factor * FONT_WIDTH));
|
||||
unsigned y = (i / BMP_ATLAS_COLS) *
|
||||
handle->scale_factor * FONT_HEIGHT;
|
||||
(BMP_ATLAS_PADDING + (handle->scale_factor * FONT_HEIGHT));
|
||||
|
||||
char_to_texture(handle, i, x, y);
|
||||
|
||||
|
@ -48,6 +48,10 @@
|
||||
#define FT_ATLAS_ROWS 16
|
||||
#define FT_ATLAS_COLS 16
|
||||
#define FT_ATLAS_SIZE (FT_ATLAS_ROWS * FT_ATLAS_COLS)
|
||||
/* Padding is required between each glyph in
|
||||
* the atlas to prevent texture bleed when
|
||||
* drawing with linear filtering enabled */
|
||||
#define FT_ATLAS_PADDING 1
|
||||
|
||||
typedef struct freetype_atlas_slot
|
||||
{
|
||||
@ -64,6 +68,8 @@ typedef struct freetype_renderer
|
||||
struct font_atlas atlas; /* ptr alignment */
|
||||
freetype_atlas_slot_t atlas_slots[FT_ATLAS_SIZE]; /* ptr alignment */
|
||||
freetype_atlas_slot_t* uc_map[0x100]; /* ptr alignment */
|
||||
unsigned max_glyph_width;
|
||||
unsigned max_glyph_height;
|
||||
unsigned usage_counter;
|
||||
struct font_line_metrics line_metrics; /* float alignment */
|
||||
} ft_font_renderer_t;
|
||||
@ -165,13 +171,35 @@ static const struct font_glyph *font_renderer_ft_get_glyph(
|
||||
|
||||
if (slot->bitmap.buffer)
|
||||
{
|
||||
unsigned r, c;
|
||||
const uint8_t *src = (const uint8_t*)slot->bitmap.buffer;
|
||||
const uint8_t *src = (const uint8_t*)slot->bitmap.buffer;
|
||||
unsigned delta_width = (handle->max_glyph_width > atlas_slot->glyph.width) ?
|
||||
(handle->max_glyph_width - atlas_slot->glyph.width) : 0;
|
||||
unsigned x, y;
|
||||
|
||||
for (r = 0; r < atlas_slot->glyph.height;
|
||||
r++, dst += handle->atlas.width, src += slot->bitmap.pitch)
|
||||
for (c = 0; c < atlas_slot->glyph.width; c++)
|
||||
dst[c] = src[c];
|
||||
/* When copying the glyph bitmap, it is
|
||||
* necessary to clear any unused regions of
|
||||
* the atlas texture, otherwise garbage
|
||||
* (due to texture bleeding) may be drawn at
|
||||
* the edges of the glyph when rendering with
|
||||
* filtering enabled */
|
||||
|
||||
for (y = 0; y < atlas_slot->glyph.height; y++)
|
||||
{
|
||||
/* Copy bitmap row */
|
||||
memcpy(dst, src, atlas_slot->glyph.width * sizeof(uint8_t));
|
||||
/* Zero out remaining atlas row */
|
||||
memset(dst + atlas_slot->glyph.width, 0, delta_width * sizeof(uint8_t));
|
||||
|
||||
dst += handle->atlas.width;
|
||||
src += slot->bitmap.pitch;
|
||||
}
|
||||
|
||||
/* Zero out unused atlas rows */
|
||||
for (y = atlas_slot->glyph.height; y < handle->max_glyph_height; y++)
|
||||
{
|
||||
memset(dst, 0, handle->max_glyph_width * sizeof(uint8_t));
|
||||
dst += handle->atlas.width;
|
||||
}
|
||||
}
|
||||
|
||||
handle->atlas.dirty = true;
|
||||
@ -184,12 +212,11 @@ static bool font_renderer_create_atlas(ft_font_renderer_t *handle, float font_si
|
||||
unsigned i, x, y;
|
||||
freetype_atlas_slot_t* slot = NULL;
|
||||
|
||||
unsigned max_width = round((handle->face->bbox.xMax - handle->face->bbox.xMin) * font_size / handle->face->units_per_EM);
|
||||
unsigned max_width = round((handle->face->bbox.xMax - handle->face->bbox.xMin) * font_size / handle->face->units_per_EM);
|
||||
unsigned max_height = round((handle->face->bbox.yMax - handle->face->bbox.yMin) * font_size / handle->face->units_per_EM);
|
||||
|
||||
unsigned atlas_width = max_width * FT_ATLAS_COLS;
|
||||
|
||||
unsigned atlas_height = max_height * FT_ATLAS_ROWS;
|
||||
unsigned atlas_width = (max_width + FT_ATLAS_PADDING) * FT_ATLAS_COLS;
|
||||
unsigned atlas_height = (max_height + FT_ATLAS_PADDING) * FT_ATLAS_ROWS;
|
||||
|
||||
uint8_t *atlas_buffer = (uint8_t*)
|
||||
calloc(atlas_width * atlas_height, 1);
|
||||
@ -197,6 +224,8 @@ static bool font_renderer_create_atlas(ft_font_renderer_t *handle, float font_si
|
||||
if (!atlas_buffer)
|
||||
return false;
|
||||
|
||||
handle->max_glyph_width = max_width;
|
||||
handle->max_glyph_height = max_height;
|
||||
handle->atlas.buffer = atlas_buffer;
|
||||
handle->atlas.width = atlas_width;
|
||||
handle->atlas.height = atlas_height;
|
||||
@ -206,8 +235,8 @@ static bool font_renderer_create_atlas(ft_font_renderer_t *handle, float font_si
|
||||
{
|
||||
for (x = 0; x < FT_ATLAS_COLS; x++)
|
||||
{
|
||||
slot->glyph.atlas_offset_x = x * max_width;
|
||||
slot->glyph.atlas_offset_y = y * max_height;
|
||||
slot->glyph.atlas_offset_x = x * (max_width + FT_ATLAS_PADDING);
|
||||
slot->glyph.atlas_offset_y = y * (max_height + FT_ATLAS_PADDING);
|
||||
slot++;
|
||||
}
|
||||
}
|
||||
|
@ -86,6 +86,9 @@ static bool font_renderer_stb_create_atlas(stb_font_renderer_t *self,
|
||||
if (!self->atlas.buffer)
|
||||
goto error;
|
||||
|
||||
/* Note: 1 pixel of padding is added to
|
||||
* prevent texture bleed when drawing with
|
||||
* linear filtering enabled */
|
||||
stbtt_PackBegin(&pc, self->atlas.buffer,
|
||||
self->atlas.width, self->atlas.height,
|
||||
self->atlas.width, 1, NULL);
|
||||
|
@ -42,6 +42,10 @@
|
||||
#define STB_UNICODE_ATLAS_ROWS 16
|
||||
#define STB_UNICODE_ATLAS_COLS 16
|
||||
#define STB_UNICODE_ATLAS_SIZE (STB_UNICODE_ATLAS_ROWS * STB_UNICODE_ATLAS_COLS)
|
||||
/* Padding is required between each glyph in
|
||||
* the atlas to prevent texture bleed when
|
||||
* drawing with linear filtering enabled */
|
||||
#define STB_UNICODE_ATLAS_PADDING 1
|
||||
|
||||
typedef struct stb_unicode_atlas_slot
|
||||
{
|
||||
@ -195,8 +199,8 @@ static bool font_renderer_stb_unicode_create_atlas(
|
||||
self->max_glyph_width = font_size < 0 ? -font_size : font_size;
|
||||
self->max_glyph_height = font_size < 0 ? -font_size : font_size;
|
||||
|
||||
self->atlas.width = self->max_glyph_width * STB_UNICODE_ATLAS_COLS;
|
||||
self->atlas.height = self->max_glyph_height * STB_UNICODE_ATLAS_ROWS;
|
||||
self->atlas.width = (self->max_glyph_width + STB_UNICODE_ATLAS_PADDING) * STB_UNICODE_ATLAS_COLS;
|
||||
self->atlas.height = (self->max_glyph_height + STB_UNICODE_ATLAS_PADDING) * STB_UNICODE_ATLAS_ROWS;
|
||||
|
||||
self->atlas.buffer = (uint8_t*)
|
||||
calloc(self->atlas.width * self->atlas.height, sizeof(uint8_t));
|
||||
@ -210,8 +214,8 @@ static bool font_renderer_stb_unicode_create_atlas(
|
||||
{
|
||||
for (x = 0; x < STB_UNICODE_ATLAS_COLS; x++)
|
||||
{
|
||||
slot->glyph.atlas_offset_x = x * self->max_glyph_width;
|
||||
slot->glyph.atlas_offset_y = y * self->max_glyph_height;
|
||||
slot->glyph.atlas_offset_x = x * (self->max_glyph_width + STB_UNICODE_ATLAS_PADDING);
|
||||
slot->glyph.atlas_offset_y = y * (self->max_glyph_height + STB_UNICODE_ATLAS_PADDING);
|
||||
slot++;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user