Skip to content

Commit

Permalink
Fixed bug 3491 - TTF_RenderText_Blended ignores alpha channel
Browse files Browse the repository at this point in the history
xyzdragon

The last argument "TTF_RenderText_Blended" takes is "SDL_Color fg". SDL_Color in turn has the members r,g,b,a. But member a is completely ignored with no mention in the documentation here https://www.libsdl.org/projects/docs/SDL_ttf/SDL_ttf_44.html

Either the alpha channel should be heeded or it should be explicitly mentioned that it isn't in the documentation, because the SDL_Color struct implies that fg.a will be processed. I hoped instead of the alpha channel of the rendering being in 0..255 that it would be in 0..fg.a, i.e. every alpha value would be multiplied by fg.a/255.
  • Loading branch information
slouken committed Sep 10, 2017
1 parent 90a83a6 commit f909e4b
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 39 deletions.
2 changes: 2 additions & 0 deletions CHANGES.txt
@@ -1,4 +1,6 @@
2.0.15:
Sam Lantinga - Sun Sep 10 00:18:45 PDT 2017
* Text rendering functions now use the alpha component of the text colors
Sam Lantinga - Sat Sep 9 22:21:55 PDT 2017
* Added support for characters greater than 0xFFFF (e.g. emoji) in the UTF-8 APIs

Expand Down
65 changes: 57 additions & 8 deletions SDL_ttf.c
Expand Up @@ -1426,6 +1426,7 @@ SDL_Surface *TTF_RenderUTF8_Solid(TTF_Font *font,
palette->colors[1].r = fg.r;
palette->colors[1].g = fg.g;
palette->colors[1].b = fg.b;
palette->colors[1].a = fg.a ? fg.a : SDL_ALPHA_OPAQUE;
SDL_SetColorKey(textbuf, SDL_TRUE, 0);

/* check kerning */
Expand Down Expand Up @@ -1569,6 +1570,7 @@ SDL_Surface *TTF_RenderUTF8_Shaded(TTF_Font *font,
int rdiff;
int gdiff;
int bdiff;
int adiff;
Uint8* src;
Uint8* dst;
Uint8* dst_check;
Expand Down Expand Up @@ -1598,16 +1600,29 @@ SDL_Surface *TTF_RenderUTF8_Shaded(TTF_Font *font,
that may occur. */
dst_check = (Uint8*)textbuf->pixels + textbuf->pitch * textbuf->h;

/* Support alpha blending */
if (!fg.a) {
fg.a = SDL_ALPHA_OPAQUE;
}
if (!bg.a) {
bg.a = SDL_ALPHA_OPAQUE;
}
if (fg.a != SDL_ALPHA_OPAQUE || bg.a != SDL_ALPHA_OPAQUE) {
SDL_SetSurfaceBlendMode(textbuf, SDL_BLENDMODE_BLEND);
}

/* Fill the palette with NUM_GRAYS levels of shading from bg to fg */
palette = textbuf->format->palette;
rdiff = fg.r - bg.r;
gdiff = fg.g - bg.g;
bdiff = fg.b - bg.b;
adiff = fg.a - bg.a;

for (index = 0; index < NUM_GRAYS; ++index) {
palette->colors[index].r = bg.r + (index*rdiff) / (NUM_GRAYS-1);
palette->colors[index].g = bg.g + (index*gdiff) / (NUM_GRAYS-1);
palette->colors[index].b = bg.b + (index*bdiff) / (NUM_GRAYS-1);
palette->colors[index].a = bg.a + (index*adiff) / (NUM_GRAYS-1);
}

/* check kerning */
Expand Down Expand Up @@ -1744,10 +1759,12 @@ SDL_Surface *TTF_RenderUTF8_Blended(TTF_Font *font,
const char *text, SDL_Color fg)
{
SDL_bool first;
int i;
int xstart;
int width, height;
SDL_Surface *textbuf;
Uint32 alpha;
Uint8 alpha;
Uint8 alpha_table[256];
Uint32 pixel;
Uint8 *src;
Uint32 *dst;
Expand Down Expand Up @@ -1781,6 +1798,21 @@ SDL_Surface *TTF_RenderUTF8_Blended(TTF_Font *font,
/* check kerning */
use_kerning = FT_HAS_KERNING(font->face) && font->kerning;

/* Support alpha blending */
if (!fg.a) {
fg.a = SDL_ALPHA_OPAQUE;
}
if (fg.a == SDL_ALPHA_OPAQUE) {
for (i = 0; i < SDL_arraysize(alpha_table); ++i) {
alpha_table[i] = (Uint8)i;
}
} else {
for (i = 0; i < SDL_arraysize(alpha_table); ++i) {
alpha_table[i] = (Uint8)(i * fg.a / 255);
}
SDL_SetSurfaceBlendMode(textbuf, SDL_BLENDMODE_BLEND);
}

/* Load and render each character */
textlen = SDL_strlen(text);
first = SDL_TRUE;
Expand Down Expand Up @@ -1838,7 +1870,7 @@ SDL_Surface *TTF_RenderUTF8_Blended(TTF_Font *font,
src = (Uint8*) (glyph->pixmap.buffer + glyph->pixmap.pitch * row);
for (col = width; col>0 && dst < dst_check; --col) {
alpha = *src++;
*dst++ |= pixel | (alpha << 24);
*dst++ |= pixel | ((Uint32)alpha_table[alpha] << 24);
}
}

Expand All @@ -1852,13 +1884,13 @@ SDL_Surface *TTF_RenderUTF8_Blended(TTF_Font *font,
/* Handle the underline style */
if (TTF_HANDLE_STYLE_UNDERLINE(font)) {
row = TTF_underline_top_row(font);
TTF_drawLine_Blended(font, textbuf, row, pixel);
TTF_drawLine_Blended(font, textbuf, row, pixel | (Uint32)fg.a << 24);
}

/* Handle the strikethrough style */
if (TTF_HANDLE_STYLE_STRIKETHROUGH(font)) {
row = TTF_strikethrough_top_row(font);
TTF_drawLine_Blended(font, textbuf, row, pixel);
TTF_drawLine_Blended(font, textbuf, row, pixel | (Uint32)fg.a << 24);
}
return(textbuf);
}
Expand Down Expand Up @@ -1916,10 +1948,12 @@ SDL_Surface *TTF_RenderUTF8_Blended_Wrapped(TTF_Font *font,
const char *text, SDL_Color fg, Uint32 wrapLength)
{
SDL_bool first;
int i;
int xstart;
int width, height;
SDL_Surface *textbuf;
Uint32 alpha;
Uint8 alpha;
Uint8 alpha_table[256];
Uint32 pixel;
Uint8 *src;
Uint32 *dst;
Expand Down Expand Up @@ -2046,6 +2080,21 @@ SDL_Surface *TTF_RenderUTF8_Blended_Wrapped(TTF_Font *font,
/* check kerning */
use_kerning = FT_HAS_KERNING(font->face) && font->kerning;

/* Support alpha blending */
if (!fg.a) {
fg.a = SDL_ALPHA_OPAQUE;
}
if (fg.a == SDL_ALPHA_OPAQUE) {
for (i = 0; i < SDL_arraysize(alpha_table); ++i) {
alpha_table[i] = (Uint8)i;
}
} else {
for (i = 0; i < SDL_arraysize(alpha_table); ++i) {
alpha_table[i] = (Uint8)(i * fg.a / 255);
}
SDL_SetSurfaceBlendMode(textbuf, SDL_BLENDMODE_BLEND);
}

/* Load and render each character */
pixel = (fg.r<<16)|(fg.g<<8)|fg.b;
SDL_FillRect(textbuf, NULL, pixel); /* Initialize with fg and 0 alpha */
Expand Down Expand Up @@ -2112,7 +2161,7 @@ SDL_Surface *TTF_RenderUTF8_Blended_Wrapped(TTF_Font *font,
src = (Uint8*) (glyph->pixmap.buffer + glyph->pixmap.pitch * row);
for (col = width; col>0 && dst < dst_check; --col) {
alpha = *src++;
*dst++ |= pixel | (alpha << 24);
*dst++ |= pixel | ((Uint32)alpha_table[alpha] << 24);
}
}

Expand All @@ -2126,14 +2175,14 @@ SDL_Surface *TTF_RenderUTF8_Blended_Wrapped(TTF_Font *font,
/* Handle the underline style *
if (TTF_HANDLE_STYLE_UNDERLINE(font)) {
row = TTF_underline_top_row(font);
TTF_drawLine_Blended(font, textbuf, row, pixel);
TTF_drawLine_Blended(font, textbuf, row, pixel | (Uint32)fg.a << 24);
}
*/

/* Handle the strikethrough style *
if (TTF_HANDLE_STYLE_STRIKETHROUGH(font)) {
row = TTF_strikethrough_top_row(font);
TTF_drawLine_Blended(font, textbuf, row, pixel);
TTF_drawLine_Blended(font, textbuf, row, pixel | (Uint32)fg.a << 24);
}
*/
}
Expand Down
97 changes: 66 additions & 31 deletions showfont.c
Expand Up @@ -21,9 +21,6 @@

/* A simple program to test the text rendering feature of the TTF library */

/* quiet windows compiler warnings */
#define _CRT_SECURE_NO_WARNINGS

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
Expand All @@ -38,7 +35,14 @@
#define HEIGHT 480

static char *Usage =
"Usage: %s [-solid] [-utf8|-unicode] [-b] [-i] [-u] [-s] [-outline size] [-hintlight|-hintmono|-hintnone] [-nokerning] [-fgcol r,g,b] [-bgcol r,g,b] <font>.ttf [ptsize] [text]\n";
"Usage: %s [-solid] [-shaded] [-blended] [-utf8|-unicode] [-b] [-i] [-u] [-s] [-outline size] [-hintlight|-hintmono|-hintnone] [-nokerning] [-fgcol r,g,b,a] [-bgcol r,g,b,a] <font>.ttf [ptsize] [text]\n";

typedef enum
{
TextRenderSolid,
TextRenderShaded,
TextRenderBlended
} TextRenderMethod;

typedef struct {
SDL_Texture *caption;
Expand Down Expand Up @@ -80,7 +84,7 @@ int main(int argc, char *argv[])
SDL_Color *forecol;
SDL_Color *backcol;
SDL_Event event;
int rendersolid;
TextRenderMethod rendermethod;
int renderstyle;
int outline;
int hinting;
Expand All @@ -96,7 +100,7 @@ int main(int argc, char *argv[])
/* Look for special execution mode */
dump = 0;
/* Look for special rendering types */
rendersolid = 0;
rendermethod = TextRenderShaded;
renderstyle = TTF_STYLE_NORMAL;
rendertype = RENDER_LATIN1;
outline = 0;
Expand All @@ -107,7 +111,13 @@ int main(int argc, char *argv[])
backcol = &white;
for (i=1; argv[i] && argv[i][0] == '-'; ++i) {
if (strcmp(argv[i], "-solid") == 0) {
rendersolid = 1;
rendermethod = TextRenderSolid;
} else
if (strcmp(argv[i], "-shaded") == 0) {
rendermethod = TextRenderShaded;
} else
if (strcmp(argv[i], "-blended") == 0) {
rendermethod = TextRenderBlended;
} else
if (strcmp(argv[i], "-utf8") == 0) {
rendertype = RENDER_UTF8;
Expand Down Expand Up @@ -149,24 +159,26 @@ int main(int argc, char *argv[])
dump = 1;
} else
if (strcmp(argv[i], "-fgcol") == 0) {
int r, g, b;
if (sscanf (argv[++i], "%d,%d,%d", &r, &g, &b) != 3) {
int r, g, b, a = 0xFF;
if (sscanf (argv[++i], "%d,%d,%d,%d", &r, &g, &b, &a) < 3) {
fprintf(stderr, Usage, argv0);
return(1);
}
forecol->r = (Uint8)r;
forecol->g = (Uint8)g;
forecol->b = (Uint8)b;
forecol->a = (Uint8)a;
} else
if (strcmp(argv[i], "-bgcol") == 0) {
int r, g, b;
if (sscanf (argv[++i], "%d,%d,%d", &r, &g, &b) != 3) {
int r, g, b, a = 0xFF;
if (sscanf (argv[++i], "%d,%d,%d,%d", &r, &g, &b, &a) < 3) {
fprintf(stderr, Usage, argv0);
return(1);
}
backcol->r = (Uint8)r;
backcol->g = (Uint8)g;
backcol->b = (Uint8)b;
backcol->a = (Uint8)a;
} else {
fprintf(stderr, Usage, argv0);
return(1);
Expand Down Expand Up @@ -234,10 +246,16 @@ int main(int argc, char *argv[])

/* Show which font file we're looking at */
SDL_snprintf(string, sizeof(string), "Font file: %s", argv[0]); /* possible overflow */
if (rendersolid) {
switch (rendermethod) {
case TextRenderSolid:
text = TTF_RenderText_Solid(font, string, *forecol);
} else {
break;
case TextRenderShaded:
text = TTF_RenderText_Shaded(font, string, *forecol, *backcol);
break;
case TextRenderBlended:
text = TTF_RenderText_Blended(font, string, *forecol);
break;
}
if (text != NULL) {
scene.captionRect.x = 4;
Expand All @@ -256,34 +274,51 @@ int main(int argc, char *argv[])
}
switch (rendertype) {
case RENDER_LATIN1:
if (rendersolid) {
text = TTF_RenderText_Solid(font,message,*forecol);
} else {
text = TTF_RenderText_Shaded(font,message,*forecol,*backcol);
}
break;
switch (rendermethod) {
case TextRenderSolid:
text = TTF_RenderText_Solid(font, message, *forecol);
break;
case TextRenderShaded:
text = TTF_RenderText_Shaded(font, message, *forecol, *backcol);
break;
case TextRenderBlended:
text = TTF_RenderText_Blended(font, message, *forecol);
break;
}
break;

case RENDER_UTF8:
if (rendersolid) {
text = TTF_RenderUTF8_Solid(font,message,*forecol);
} else {
text = TTF_RenderUTF8_Shaded(font,message,*forecol,*backcol);
}
break;
switch (rendermethod) {
case TextRenderSolid:
text = TTF_RenderUTF8_Solid(font, message, *forecol);
break;
case TextRenderShaded:
text = TTF_RenderUTF8_Shaded(font, message, *forecol, *backcol);
break;
case TextRenderBlended:
text = TTF_RenderUTF8_Blended(font, message, *forecol);
break;
}
break;

case RENDER_UNICODE:
{
Uint16 *unicode_text = SDL_iconv_utf8_ucs2(message);
if (rendersolid) {
text = TTF_RenderUNICODE_Solid(font,
unicode_text, *forecol);
} else {
text = TTF_RenderUNICODE_Shaded(font,
unicode_text, *forecol, *backcol);
switch (rendermethod) {
case TextRenderSolid:
text = TTF_RenderUNICODE_Solid(font, unicode_text, *forecol);
break;
case TextRenderShaded:
text = TTF_RenderUNICODE_Shaded(font, unicode_text, *forecol, *backcol);
break;
case TextRenderBlended:
text = TTF_RenderUNICODE_Blended(font, unicode_text, *forecol);
break;
}
SDL_free(unicode_text);
}
break;

default:
text = NULL; /* This shouldn't happen */
break;
Expand Down

0 comments on commit f909e4b

Please sign in to comment.