Bitmap: Add font shadow rendering

This commit is contained in:
Jonas Kulla 2014-09-29 10:30:41 +02:00
parent 9e64dff01c
commit 4a015c6397
2 changed files with 92 additions and 4 deletions

View File

@ -7,10 +7,6 @@ It is licensed under the GNU General Public License v2+.
## RGSS2 / RGSS3 ## RGSS2 / RGSS3
Support for these RGSS versions is experimental. A lot is implemented (to the point that you can play the VX Ace sample game, with caveats), but not everything is in place yet. Support for these RGSS versions is experimental. A lot is implemented (to the point that you can play the VX Ace sample game, with caveats), but not everything is in place yet.
Missing RGSS2 functionality:
* Text shadow
Missing RGSS3 functionality: Missing RGSS3 functionality:
* Text outline * Text outline

View File

@ -838,6 +838,93 @@ static std::string fixupString(const char *str)
return s; return s;
} }
static void applyShadow(SDL_Surface *&in, const SDL_PixelFormat &fm, const SDL_Color &c)
{
SDL_Surface *out = SDL_CreateRGBSurface
(0, in->w+1, in->h+1, fm.BitsPerPixel, fm.Rmask, fm.Gmask, fm.Bmask, fm.Amask);
float fr = c.r / 255.0;
float fg = c.g / 255.0;
float fb = c.b / 255.0;
/* We allocate an output surface one pixel wider and higher than the input,
* (implicitly) blit a copy of the input with RGB values set to black into
* it with x/y offset by 1, then blend the input surface over it at origin
* (0,0) using the bitmap blit equation (see shader/bitmapBlit.frag) */
for (int y = 0; y < in->h+1; ++y)
for (int x = 0; x < in->w+1; ++x)
{
/* src: input pixel, shd: shadow pixel */
uint32_t src = 0, shd = 0;
/* Output pixel location */
uint32_t *outP = ((uint32_t*) ((uint8_t*) out->pixels + y*out->pitch)) + x;
if (y < in->h && x < in->w)
src = ((uint32_t*) ((uint8_t*) in->pixels + y*in->pitch))[x];
if (y > 0 && x > 0)
shd = ((uint32_t*) ((uint8_t*) in->pixels + (y-1)*in->pitch))[x-1];
/* Set shadow pixel RGB values to 0 (black) */
shd &= fm.Amask;
if (x == 0 || y == 0)
{
*outP = src;
continue;
}
if (x == in->w || y == in->h)
{
*outP = shd;
continue;
}
/* Input and shadow alpha values */
uint8_t srcA, shdA;
srcA = (src & fm.Amask) >> fm.Ashift;
shdA = (shd & fm.Amask) >> fm.Ashift;
if (srcA == 255 || shdA == 0)
{
*outP = src;
continue;
}
if (srcA == 0 && shdA == 0)
{
*outP = 0;
continue;
}
float fSrcA = srcA / 255.0;
float fShdA = shdA / 255.0;
/* Because opacity == 1, co1 == fSrcA */
float co2 = fShdA * (1.0 - fSrcA);
/* Result alpha */
float fa = fSrcA + co2;
/* Temp value to simplify arithmetic below */
float co3 = fSrcA / fa;
/* Result colors */
uint8_t r, g, b, a;
r = clamp<float>(fr * co3, 0, 1) * 255;
g = clamp<float>(fg * co3, 0, 1) * 255;
b = clamp<float>(fb * co3, 0, 1) * 255;
a = clamp<float>(fa, 0, 1) * 255;
*outP = SDL_MapRGBA(&fm, r, g, b, a);
}
/* Store new surface in the input pointer */
SDL_FreeSurface(in);
in = out;
}
void Bitmap::drawText(const IntRect &rect, const char *str, int align) void Bitmap::drawText(const IntRect &rect, const char *str, int align)
{ {
guardDisposed(); guardDisposed();
@ -870,6 +957,11 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align)
p->ensureFormat(txtSurf, SDL_PIXELFORMAT_ABGR8888); p->ensureFormat(txtSurf, SDL_PIXELFORMAT_ABGR8888);
// While real outlining is not yet here, use shadow
// as a replacement to at least make text legible
if (p->font->getShadow() || p->font->getOutline())
applyShadow(txtSurf, *p->format, c);
int alignX = rect.x; int alignX = rect.x;
switch (align) switch (align)