diff options
author | 2020-09-20 11:39:28 +1000 | |
---|---|---|
committer | 2020-09-20 11:39:28 +1000 | |
commit | dbb277456c11389ae4fd30132786753caacfbf5f (patch) | |
tree | b3c4e9504fac0279f200af13deed628148d1af62 /src/emu/rendlay.cpp | |
parent | 1049b305d644b0eb66686ab9802ff8b2cd12d9d4 (diff) |
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.
Diffstat (limited to 'src/emu/rendlay.cpp')
-rw-r--r-- | src/emu/rendlay.cpp | 111 |
1 files changed, 61 insertions, 50 deletions
diff --git a/src/emu/rendlay.cpp b/src/emu/rendlay.cpp index 6e5f795a70b..46502185e29 100644 --- a/src/emu/rendlay.cpp +++ b/src/emu/rendlay.cpp @@ -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) + { + // 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) { - for (u32 x = bounds.left(); x <= bounds.right(); x++) + // 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 + *dst = rgb_t(finala / 255, finalr / finala, finalg / finala, finalb / finala); } - - // store the target pixel, dividing the RGBA values by the overall scale factor - dest.pix32(y, x) = rgb_t(finalr, finalg, finalb); } } } @@ -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 + *dst = rgb_t(finala / 255, finalr / finala, finalg / finala, finalb / finala); } - - // store the target pixel, dividing the RGBA values by the overall scale factor - dest.pix32(y, x) = rgb_t(finalr, finalg, finalb); } } } |