diff --git a/src/SMAPI/Framework/Content/AssetDataForImage.cs b/src/SMAPI/Framework/Content/AssetDataForImage.cs
index f59e73bea..f6c1e46a6 100644
--- a/src/SMAPI/Framework/Content/AssetDataForImage.cs
+++ b/src/SMAPI/Framework/Content/AssetDataForImage.cs
@@ -213,22 +213,47 @@ private void PatchImageImpl(Color[] sourceData, int sourceWidth, int sourceHeigh
// shortcut transparency
if (above.A < AssetDataForImage.MinOpacity)
continue;
- if (below.A < AssetDataForImage.MinOpacity || above.A == byte.MaxValue)
- mergedData[targetIndex] = above;
- // merge pixels
+ if (patchMode == PatchMode.Overlay)
+ {
+ if (below.A < AssetDataForImage.MinOpacity || above.A == byte.MaxValue)
+ mergedData[targetIndex] = above;
+
+ // merge pixels
+ else
+ {
+ // This performs a conventional alpha blend for the pixels, which are already
+ // premultiplied by the content pipeline. The formula is derived from
+ // https://blogs.msdn.microsoft.com/shawnhar/2009/11/06/premultiplied-alpha/.
+ float alphaBelow = 1 - (above.A / 255f);
+ mergedData[targetIndex] = new Color(
+ r: (int)(above.R + (below.R * alphaBelow)),
+ g: (int)(above.G + (below.G * alphaBelow)),
+ b: (int)(above.B + (below.B * alphaBelow)),
+ alpha: Math.Max(above.A, below.A)
+ );
+ }
+ }
else
{
- // This performs a conventional alpha blend for the pixels, which are already
- // premultiplied by the content pipeline. The formula is derived from
- // https://blogs.msdn.microsoft.com/shawnhar/2009/11/06/premultiplied-alpha/.
- float alphaBelow = 1 - (above.A / 255f);
- mergedData[targetIndex] = new Color(
- r: (int)(above.R + (below.R * alphaBelow)),
- g: (int)(above.G + (below.G * alphaBelow)),
- b: (int)(above.B + (below.B * alphaBelow)),
- alpha: Math.Max(above.A, below.A)
- );
+ // compute new alpha by subtracting mask alpha
+ int newAlphaInt = below.A - above.A;
+
+ // fully masked out
+ if (newAlphaInt <= 0)
+ mergedData[targetIndex] = new Color((byte)0, (byte)0, (byte)0, (byte)0);
+
+ else
+ {
+ // This blends the pixels by removing the alpha defined in the mask.
+ float scale = (float)newAlphaInt / below.A;
+ mergedData[targetIndex] = new Color(
+ r: (int)Math.Clamp(Math.Round(below.R * scale), 0, 255),
+ g: (int)Math.Clamp(Math.Round(below.G * scale), 0, 255),
+ b: (int)Math.Clamp(Math.Round(below.B * scale), 0, 255),
+ alpha: newAlphaInt
+ );
+ }
}
}
diff --git a/src/SMAPI/PatchMode.cs b/src/SMAPI/PatchMode.cs
index 8575e5d0b..669a0f035 100644
--- a/src/SMAPI/PatchMode.cs
+++ b/src/SMAPI/PatchMode.cs
@@ -7,5 +7,8 @@ public enum PatchMode
Replace,
/// Draw the new content over the original content, so the original content shows through any transparent or semi-transparent pixels.
- Overlay
+ Overlay,
+
+ /// Masks the original content so that the alpha value of every pixel in the new content gets subtracted from the corresponding pixel in the original content.
+ Mask
}