rendlay.cpp: Correct output alpha for rect and disk components.

This corrects alpha for cases when both the rect/disk and whatever it's
drawing over are translucent, and also optimises for fully opaque and
fully transparent pixels.
This commit is contained in:
Vas Crabb 2020-09-20 11:39:28 +10:00
parent 1049b305d6
commit dbb277456c
2 changed files with 64 additions and 53 deletions

View File

@ -1465,33 +1465,39 @@ protected:
// overrides
virtual void draw(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
{
// compute premultiplied colors
render_color const c = color(state);
u32 const r = c.r * c.a * 255.0f;
u32 const g = c.g * c.a * 255.0f;
u32 const b = c.b * c.a * 255.0f;
u32 const inva = (1.0f - c.a) * 255.0f;
// iterate over X and Y
for (u32 y = bounds.top(); y <= bounds.bottom(); y++)
render_color const c(color(state));
if (1.0f <= c.a)
{
for (u32 x = bounds.left(); x <= bounds.right(); x++)
// optimise opaque pixels
u32 const f(rgb_t(u8(c.r * 255), u8(c.g * 255), u8(c.b * 255)));
s32 const width(bounds.width());
for (u32 y = bounds.top(); y <= bounds.bottom(); ++y)
std::fill_n(&dest.pix(y, bounds.left()), width, f);
}
else if (c.a)
{
// compute premultiplied colors
u32 const a(c.a * 255.0F);
u32 const r(c.r * c.a * (255.0F * 255.0F));
u32 const g(c.g * c.a * (255.0F * 255.0F));
u32 const b(c.b * c.a * (255.0F * 255.0F));
u32 const inva(255 - a);
// we're translucent, add in the destination pixel contribution
for (u32 y = bounds.top(); y <= bounds.bottom(); ++y)
{
u32 finalr = r;
u32 finalg = g;
u32 finalb = b;
// if we're translucent, add in the destination pixel contribution
if (inva > 0)
u32 *dst(&dest.pix(y, bounds.left()));
for (u32 x = bounds.left(); x <= bounds.right(); ++x, ++dst)
{
rgb_t dpix = dest.pix32(y, x);
finalr += (dpix.r() * inva) >> 8;
finalg += (dpix.g() * inva) >> 8;
finalb += (dpix.b() * inva) >> 8;
}
rgb_t const dpix(*dst);
u32 const finala((a * 255) + (dpix.a() * inva));
u32 const finalr(r + (dpix.r() * inva));
u32 const finalg(g + (dpix.g() * inva));
u32 const finalb(b + (dpix.b() * inva));
// store the target pixel, dividing the RGBA values by the overall scale factor
dest.pix32(y, x) = rgb_t(finalr, finalg, finalb);
// store the target pixel, dividing the RGBA values by the overall scale factor
*dst = rgb_t(finala / 255, finalr / finala, finalg / finala, finalb / finala);
}
}
}
}
@ -1514,46 +1520,51 @@ protected:
{
// compute premultiplied colors
render_color const c(color(state));
u32 const r = c.r * c.a * 255.0f;
u32 const g = c.g * c.a * 255.0f;
u32 const b = c.b * c.a * 255.0f;
u32 const inva = (1.0f - c.a) * 255.0f;
u32 const f(rgb_t(u8(c.r * 255), u8(c.g * 255), u8(c.b * 255)));
u32 const a(c.a * 255.0F);
u32 const r(c.r * c.a * (255.0F * 255.0F));
u32 const g(c.g * c.a * (255.0F * 255.0F));
u32 const b(c.b * c.a * (255.0F * 255.0F));
u32 const inva(255 - a);
// find the center
float const xcenter = float(bounds.xcenter());
float const ycenter = float(bounds.ycenter());
float const xradius = float(bounds.width()) * 0.5f;
float const yradius = float(bounds.height()) * 0.5f;
float const ooyradius2 = 1.0f / (yradius * yradius);
float const xradius = float(bounds.width()) * 0.5F;
float const yradius = float(bounds.height()) * 0.5F;
float const ooyradius2 = 1.0F / (yradius * yradius);
// iterate over y
for (u32 y = bounds.top(); y <= bounds.bottom(); y++)
for (u32 y = bounds.top(); y <= bounds.bottom(); ++y)
{
float ycoord = ycenter - (float(y) + 0.5f);
float xval = xradius * sqrtf(1.0f - (ycoord * ycoord) * ooyradius2);
// compute left/right coordinates
s32 left = s32(xcenter - xval + 0.5f);
s32 right = s32(xcenter + xval + 0.5f);
float const ycoord = ycenter - (float(y) + 0.5F);
float const xval = xradius * sqrtf(1.0F - (ycoord * ycoord) * ooyradius2);
s32 const left = s32(xcenter - xval + 0.5F);
s32 const right = s32(xcenter + xval + 0.5F);
// draw this scanline
for (u32 x = left; x < right; x++)
if (255 <= a)
{
u32 finalr = r;
u32 finalg = g;
u32 finalb = b;
// if we're translucent, add in the destination pixel contribution
if (inva > 0)
// optimise opaque pixels
std::fill_n(&dest.pix(y, left), right - left, f);
}
else if (a)
{
u32 *dst(&dest.pix(y, bounds.left()));
for (u32 x = left; x < right; ++x, ++dst)
{
rgb_t dpix = dest.pix32(y, x);
finalr += (dpix.r() * inva) >> 8;
finalg += (dpix.g() * inva) >> 8;
finalb += (dpix.b() * inva) >> 8;
}
// we're translucent, add in the destination pixel contribution
rgb_t const dpix(*dst);
u32 const finala((a * 255) + (dpix.a() * inva));
u32 const finalr(r + (dpix.r() * inva));
u32 const finalg(g + (dpix.g() * inva));
u32 const finalb(b + (dpix.b() * inva));
// store the target pixel, dividing the RGBA values by the overall scale factor
dest.pix32(y, x) = rgb_t(finalr, finalg, finalb);
// store the target pixel, dividing the RGBA values by the overall scale factor
*dst = rgb_t(finala / 255, finalr / finala, finalg / finala, finalb / finala);
}
}
}
}

View File

@ -74,7 +74,7 @@ license:CC0
</element>
<element name="nothing" defstate="0">
<text string=" "/>
<rect><color alpha="0" /></rect>
</element>
<element name="hlb" defstate="0">
@ -254,7 +254,7 @@ license:CC0
</element>
<element name="ani_white" defstate="0">
<text string=" "><bounds x="0" y="0" width="1" height="100" /></text>
<rect><bounds x="0" y="0" width="1" height="100" /><color alpha="0" /></rect>
<rect state="1"><bounds x="0" y="0" width="1" height="1" /><color red="1" green="1" blue="1" /></rect>
<rect state="2"><bounds x="0" y="0" width="1" height="2" /><color red="1" green="1" blue="1" /></rect>
<rect state="3"><bounds x="0" y="0" width="1" height="3" /><color red="1" green="1" blue="1" /></rect>
@ -358,7 +358,7 @@ license:CC0
</element>
<element name="ani_crate" defstate="0">
<text string=" "><bounds x="0" y="0" width="1" height="110" /></text>
<rect><bounds x="0" y="0" width="1" height="110" /><color alpha="0" /></rect>
<rect state="0"><bounds x="0" y="0" width="1" height="10" /><color red="0.75" green="0.1" blue="0.15" /></rect>
<rect state="1"><bounds x="0" y="1" width="1" height="10" /><color red="0.75" green="0.1" blue="0.15" /></rect>
<rect state="2"><bounds x="0" y="2" width="1" height="10" /><color red="0.75" green="0.1" blue="0.15" /></rect>