void NatePixTable::Frame::load_overlay(const PixMap& pix, uint8_t color) { for (auto x : range(width())) { for (auto y : range(height())) { RgbColor over = pix.get(x, y); uint8_t value = over.red; uint8_t frac = over.alpha; over = RgbColor::tint(color, value); RgbColor under = _pix_map.get(x, y); RgbColor composite; composite.red = ((over.red * frac) + (under.red * (255 - frac))) / 255; composite.green = ((over.green * frac) + (under.green * (255 - frac))) / 255; composite.blue = ((over.blue * frac) + (under.blue * (255 - frac))) / 255; composite.alpha = under.alpha; _pix_map.set(x, y, composite); } } }
void PixMap::composite(const PixMap& pix) { if (size() != pix.size()) { throw Exception("Mismatch in PixMap sizes"); } for (int y = 0; y < size().height; ++y) { for (int x = 0; x < size().width; ++x) { const RgbColor& over = pix.get(x, y); const double oa = over.alpha / 255.0; const RgbColor& under = get(x, y); const double ua = under.alpha / 255.0; // TODO(sfiera): if we're going to do anything like this in the long run, we should // require that alpha be pre-multiplied with the color components. We should probably // also use integral arithmetic. double red = (over.red * oa) + ((under.red * ua) * (1.0 - oa)); double green = (over.green * oa) + ((under.green * ua) * (1.0 - oa)); double blue = (over.blue * oa) + ((under.blue * ua) * (1.0 - oa)); double alpha = oa + (ua * (1.0 - oa)); set(x, y, RgbColor(alpha * 255, red / alpha, green / alpha, blue / alpha)); } } }