Sanitize font rendering in xv and SDL.

Fixes old bug where big chunks of fonts would often be just left out.
This commit is contained in:
Themaister 2012-09-27 01:41:35 +02:00
parent 5936fbf463
commit 2e168157c1
2 changed files with 167 additions and 100 deletions

View File

@ -143,44 +143,66 @@ static void sdl_render_msg_15(sdl_video_t *vid, SDL_Surface *buffer, const char
font_renderer_msg(vid->font, msg, &out);
struct font_output *head = out.head;
int base_x = g_settings.video.msg_pos_x * width;
int base_y = (1.0 - g_settings.video.msg_pos_y) * height;
int msg_base_x = g_settings.video.msg_pos_x * width;
int msg_base_y = (1.0 - g_settings.video.msg_pos_y) * height;
unsigned rshift = fmt->Rshift;
unsigned gshift = fmt->Gshift;
unsigned bshift = fmt->Bshift;
while (head)
for (; head; head = head->next)
{
int rbase_x = base_x + head->off_x;
int rbase_y = base_y - head->off_y;
if (rbase_y >= 0)
int base_x = msg_base_x + head->off_x;
int base_y = msg_base_y - head->off_y - head->height;
int glyph_width = head->width;
int glyph_height = head->height;
const uint8_t *src = head->output;
if (base_x < 0)
{
for (int y = 0; y < (int)head->height && (y + rbase_y) < (int)height; y++)
{
if (rbase_x < 0)
continue;
const uint8_t *a = head->output + head->pitch * y;
uint16_t *out = (uint16_t*)buffer->pixels + (rbase_y - head->height + y) * (buffer->pitch >> 1) + rbase_x;
for (int x = 0; x < (int)head->width && (x + rbase_x) < (int)width; x++)
{
unsigned blend = a[x];
unsigned out_pix = out[x];
unsigned r = (out_pix >> rshift) & 0x1f;
unsigned g = (out_pix >> gshift) & 0x1f;
unsigned b = (out_pix >> bshift) & 0x1f;
unsigned out_r = (r * (256 - blend) + vid->font_r * blend) >> 8;
unsigned out_g = (g * (256 - blend) + vid->font_g * blend) >> 8;
unsigned out_b = (b * (256 - blend) + vid->font_b * blend) >> 8;
out[x] = (out_r << rshift) | (out_g << gshift) | (out_b << bshift);
}
}
src -= base_x;
glyph_width += base_x;
base_x = 0;
}
head = head->next;
if (base_y < 0)
{
src -= base_y * (int)head->pitch;
glyph_height += base_y;
base_y = 0;
}
int max_width = width - base_x;
int max_height = height - base_y;
if (max_width <= 0 || max_height <= 0)
continue;
if (glyph_width > max_width)
glyph_width = max_width;
if (glyph_height > max_height)
glyph_height = max_height;
uint16_t *out = (uint16_t*)buffer->pixels + base_y * (buffer->pitch >> 1) + base_x;
for (int y = 0; y < glyph_height; y++, src += head->pitch, out += buffer->pitch >> 1)
{
for (int x = 0; x < glyph_width; x++)
{
unsigned blend = src[x];
unsigned out_pix = out[x];
unsigned r = (out_pix >> rshift) & 0x1f;
unsigned g = (out_pix >> gshift) & 0x1f;
unsigned b = (out_pix >> bshift) & 0x1f;
unsigned out_r = (r * (256 - blend) + vid->font_r * blend) >> 8;
unsigned out_g = (g * (256 - blend) + vid->font_g * blend) >> 8;
unsigned out_b = (b * (256 - blend) + vid->font_b * blend) >> 8;
out[x] = (out_r << rshift) | (out_g << gshift) | (out_b << bshift);
}
}
}
font_renderer_free_output(&out);
@ -204,44 +226,66 @@ static void sdl_render_msg_32(sdl_video_t *vid, SDL_Surface *buffer, const char
font_renderer_msg(vid->font, msg, &out);
struct font_output *head = out.head;
int base_x = g_settings.video.msg_pos_x * width;
int base_y = (1.0 - g_settings.video.msg_pos_y) * height;
int msg_base_x = g_settings.video.msg_pos_x * width;
int msg_base_y = (1.0 - g_settings.video.msg_pos_y) * height;
unsigned rshift = fmt->Rshift;
unsigned gshift = fmt->Gshift;
unsigned bshift = fmt->Bshift;
while (head)
for (; head; head = head->next)
{
int rbase_x = base_x + head->off_x;
int rbase_y = base_y - head->off_y;
if (rbase_y >= 0)
int base_x = msg_base_x + head->off_x;
int base_y = msg_base_y - head->off_y - head->height;
int glyph_width = head->width;
int glyph_height = head->height;
const uint8_t *src = head->output;
if (base_x < 0)
{
for (int y = 0; y < (int)head->height && (y + rbase_y) < (int)height; y++)
{
if (rbase_x < 0)
continue;
const uint8_t *a = head->output + head->pitch * y;
uint32_t *out = (uint32_t*)buffer->pixels + (rbase_y - head->height + y) * (buffer->pitch >> 2) + rbase_x;
for (int x = 0; x < (int)head->width && (x + rbase_x) < (int)width; x++)
{
unsigned blend = a[x];
unsigned out_pix = out[x];
unsigned r = (out_pix >> rshift) & 0xff;
unsigned g = (out_pix >> gshift) & 0xff;
unsigned b = (out_pix >> bshift) & 0xff;
unsigned out_r = (r * (256 - blend) + vid->font_r * blend) >> 8;
unsigned out_g = (g * (256 - blend) + vid->font_g * blend) >> 8;
unsigned out_b = (b * (256 - blend) + vid->font_b * blend) >> 8;
out[x] = (out_r << rshift) | (out_g << gshift) | (out_b << bshift);
}
}
src -= base_x;
glyph_width += base_x;
base_x = 0;
}
head = head->next;
if (base_y < 0)
{
src -= base_y * (int)head->pitch;
glyph_height += base_y;
base_y = 0;
}
int max_width = width - base_x;
int max_height = height - base_y;
if (max_width <= 0 || max_height <= 0)
continue;
if (glyph_width > max_width)
glyph_width = max_width;
if (glyph_height > max_height)
glyph_height = max_height;
uint32_t *out = (uint32_t*)buffer->pixels + base_y * (buffer->pitch >> 2) + base_x;
for (int y = 0; y < glyph_height; y++, src += head->pitch, out += buffer->pitch >> 2)
{
for (int x = 0; x < glyph_width; x++)
{
unsigned blend = src[x];
unsigned out_pix = out[x];
unsigned r = (out_pix >> rshift) & 0xff;
unsigned g = (out_pix >> gshift) & 0xff;
unsigned b = (out_pix >> bshift) & 0xff;
unsigned out_r = (r * (256 - blend) + vid->font_r * blend) >> 8;
unsigned out_g = (g * (256 - blend) + vid->font_g * blend) >> 8;
unsigned out_b = (b * (256 - blend) + vid->font_b * blend) >> 8;
out[x] = (out_r << rshift) | (out_g << gshift) | (out_b << bshift);
}
}
}
font_renderer_free_output(&out);

View File

@ -643,8 +643,8 @@ static void xv_render_msg(xv_t *xv, const char *msg, unsigned width, unsigned he
font_renderer_msg(xv->font, msg, &out);
struct font_output *head = out.head;
int _base_x = g_settings.video.msg_pos_x * width;
int _base_y = height - g_settings.video.msg_pos_y * height;
int msg_base_x = g_settings.video.msg_pos_x * width;
int msg_base_y = height * (1.0 - g_settings.video.msg_pos_y);
unsigned luma_index[2] = { xv->luma_index[0], xv->luma_index[1] };
unsigned chroma_u_index = xv->chroma_u_index;
@ -652,51 +652,74 @@ static void xv_render_msg(xv_t *xv, const char *msg, unsigned width, unsigned he
unsigned pitch = width << 1; // YUV formats used are 16 bpp.
while (head)
for (; head; head = head->next)
{
int base_x = (_base_x + head->off_x) << 1;
base_x &= ~3; // Make sure we always start on the correct boundary so the indices are correct.
int base_x = (msg_base_x + head->off_x) & ~1; // Make sure we always start on the correct boundary so the indices are correct.
int base_y = msg_base_y - head->off_y - head->height;
int base_y = _base_y - head->off_y;
if (base_y >= 0)
int glyph_width = head->width;
int glyph_height = head->height;
const uint8_t *src = head->output;
if (base_x < 0)
{
for (int y = 0; y < (int)head->height && (base_y + y) < (int)height; y++)
{
if (base_x < 0)
continue;
const uint8_t *a = head->output + head->pitch * y;
uint8_t *out = (uint8_t*)xv->image->data + (base_y - head->height + y) * pitch + base_x;
for (int x = 0; x < (int)(head->width << 1) && (base_x + x) < (int)pitch; x += 4)
{
unsigned alpha[2];
alpha[0] = a[(x >> 1) + 0];
if (((x >> 1) + 1) == (int)head->width) // We reached the end, uhoh. Branching like a BOSS. :D
alpha[1] = 0;
else
alpha[1] = a[(x >> 1) + 1];
unsigned alpha_sub = (alpha[0] + alpha[1]) >> 1; // Blended alpha for the sub-samples U/V channels.
for (unsigned i = 0; i < 2; i++)
{
unsigned blended = (xv->font_y * alpha[i] + ((256 - alpha[i]) * out[x + luma_index[i]])) >> 8;
out[x + luma_index[i]] = blended;
}
// Blend chroma channels
unsigned blended = (xv->font_u * alpha_sub + ((256 - alpha_sub) * out[x + chroma_u_index])) >> 8;
out[x + chroma_u_index] = blended;
blended = (xv->font_v * alpha_sub + ((256 - alpha_sub) * out[x + chroma_v_index])) >> 8;
out[x + chroma_v_index] = blended;
}
}
src -= base_x;
glyph_width += base_x;
base_x = 0;
}
head = head->next;
if (base_y < 0)
{
src -= base_y * (int)head->pitch;
glyph_height += base_y;
base_y = 0;
}
int max_width = width - base_x;
int max_height = height - base_y;
if (max_width <= 0 || max_height <= 0)
continue;
if (glyph_width > max_width)
glyph_width = max_width;
if (glyph_height > max_height)
glyph_height = max_height;
uint8_t *out = (uint8_t*)xv->image->data + base_y * pitch + (base_x << 1);
for (int y = 0; y < glyph_height; y++, src += head->pitch, out += pitch)
{
// 2 input pixels => 4 bytes (2Y, 1U, 1V).
for (int x = 0; x < glyph_width; x += 2)
{
int out_x = x << 1;
unsigned alpha[2];
alpha[0] = src[x + 0];
if (x + 1 < glyph_width)
alpha[1] = src[x + 1];
else
alpha[1] = 0;
unsigned alpha_sub = (alpha[0] + alpha[1]) >> 1; // Blended alpha for the sub-sampled U/V channels.
for (unsigned i = 0; i < 2; i++)
{
unsigned blended = (xv->font_y * alpha[i] + ((256 - alpha[i]) * out[out_x + luma_index[i]])) >> 8;
out[out_x + luma_index[i]] = blended;
}
// Blend chroma channels
unsigned blended = (xv->font_u * alpha_sub + ((256 - alpha_sub) * out[out_x + chroma_u_index])) >> 8;
out[out_x + chroma_u_index] = blended;
blended = (xv->font_v * alpha_sub + ((256 - alpha_sub) * out[out_x + chroma_v_index])) >> 8;
out[out_x + chroma_v_index] = blended;
}
}
}
font_renderer_free_output(&out);