Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GRAPHICS: Improve TTF rendering on transparent surfaces. #2748

Merged
merged 2 commits into from
Feb 21, 2021
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 17 additions & 8 deletions graphics/fonts/ttf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@ namespace {

template<typename ColorType>
static void renderGlyph(uint8 *dstPos, const int dstPitch, const uint8 *srcPos, const int srcPitch, const int w, const int h, ColorType color, const PixelFormat &dstFormat) {
uint8 sR, sG, sB;
uint8 sA, sR, sG, sB;
dstFormat.colorToRGB(color, sR, sG, sB);

for (int y = 0; y < h; ++y) {
Expand All @@ -594,16 +594,25 @@ static void renderGlyph(uint8 *dstPos, const int dstPitch, const uint8 *srcPos,
if (*src == 255) {
*rDst = color;
} else if (*src) {
const uint8 a = *src;
sA = *src;

uint8 dR, dG, dB;
dstFormat.colorToRGB(*rDst, dR, dG, dB);
uint8 dA, dR, dG, dB;
dstFormat.colorToARGB(*rDst, dA, dR, dG, dB);

dR = ((255 - a) * dR + a * sR) / 255;
dG = ((255 - a) * dG + a * sG) / 255;
dB = ((255 - a) * dB + a * sB) / 255;
if (dA == 0) {
*rDst = dstFormat.ARGBToColor(sA, sR, sG, sB);
} else {
double alpha = (double)sA / 255.0;
dR = static_cast<uint8>((sR * alpha) + (dR * (1.0 - alpha)));
dG = static_cast<uint8>((sG * alpha) + (dG * (1.0 - alpha)));
dB = static_cast<uint8>((sB * alpha) + (dB * (1.0 - alpha)));

*rDst = dstFormat.RGBToColor(dR, dG, dB);
if (sA > dA) {
dA = static_cast<uint8>((sA * alpha) + (dA * (1.0 - alpha)));
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where do those formula come from?
My understanding of color blending is that it should be:

double sAn = (double)sA / 255.0;
double dAn = (double)dA / 255.0;
dR = static_cast<uint8>(sR * sAn + dR * dAn * (1.0 - sAn) / (sAn + dAn * (1.0 - sAn)));
dG = static_cast<uint8>(sG * sAn + dG * dAn * (1.0 - sAn) / (sAn + dAn * (1.0 - sAn)));
dB = static_cast<uint8>(sB * sAn + dB * dAn * (1.0 - sAn) / (sAn + dAn * (1.0 - sAn)));
dA = static_cast<uint8>(sA + dA * (1.0 - sAn));

This also means there is no need for a special case if dA is 0.
And you can of course optimise that code a bit by computing dAn * (1.0 - sAn) only once instead of 6 times.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly followed suit with managed_surface.cpp:487-490
Figured if case for dA is 0 might be better to avoid calculations, but perhaps not.
Destination alpha... I just wasn't sure the best call.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, looking at https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending
If I'm understanding it correctly, what I used would be correct for dA being 255, but not complete enough for any other value.
I'll take another swing at this.

Copy link
Member Author

@OMGPizzaGuy OMGPizzaGuy Feb 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, the suggested code was great.
I went with calculating a normalized output alpha and converting that to a byte at the end.
I thought it would be a little more clear to anyone reading the code.

*rDst = dstFormat.ARGBToColor(dA, dR, dG, dB);
}
}

++rDst;
Expand Down