From b9844c4acd93411c2a7d21bd115cb4fee1791d76 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 25 Sep 2018 00:58:46 -0400 Subject: add support for semi-transparency when overlaying images --- src/SMAPI/Framework/Content/AssetDataForImage.cs | 39 ++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) (limited to 'src/SMAPI/Framework/Content') diff --git a/src/SMAPI/Framework/Content/AssetDataForImage.cs b/src/SMAPI/Framework/Content/AssetDataForImage.cs index 5c7b87de..cd372948 100644 --- a/src/SMAPI/Framework/Content/AssetDataForImage.cs +++ b/src/SMAPI/Framework/Content/AssetDataForImage.cs @@ -7,6 +7,14 @@ namespace StardewModdingAPI.Framework.Content /// Encapsulates access and changes to image content being read from a data file. internal class AssetDataForImage : AssetData, IAssetDataForImage { + /********* + ** Properties + *********/ + /// The minimum value to consider non-transparent. + /// On Linux/Mac, fully transparent pixels may have an alpha up to 4 for some reason. + private const byte MinOpacity = 5; + + /********* ** Public methods *********/ @@ -53,13 +61,38 @@ namespace StardewModdingAPI.Framework.Content // merge data in overlay mode if (patchMode == PatchMode.Overlay) { + // get target data + Color[] targetData = new Color[pixelCount]; + target.GetData(0, targetArea, targetData, 0, pixelCount); + + // merge pixels Color[] newData = new Color[targetArea.Value.Width * targetArea.Value.Height]; target.GetData(0, targetArea, newData, 0, newData.Length); for (int i = 0; i < sourceData.Length; i++) { - Color pixel = sourceData[i]; - if (pixel.A > 4) // not transparent (note: on Linux/Mac, fully transparent pixels may have an alpha up to 4 for some reason) - newData[i] = pixel; + Color above = sourceData[i]; + Color below = targetData[i]; + + // shortcut transparency + if (above.A < AssetDataForImage.MinOpacity) + continue; + if (below.A < AssetDataForImage.MinOpacity) + { + newData[i] = above; + continue; + } + + // merge pixels + // This performs a conventional alpha blend for the pixels, which are already + // premultiplied by the content pipeline. + float alphaAbove = above.A / 255f; + float alphaBelow = (255 - above.A) / 255f; + newData[i] = new Color( + r: (int)((above.R * alphaAbove) + (below.R * alphaBelow)), + g: (int)((above.G * alphaAbove) + (below.G * alphaBelow)), + b: (int)((above.B * alphaAbove) + (below.B * alphaBelow)), + a: Math.Max(above.A, below.A) + ); } sourceData = newData; } -- cgit From 43e935b01761b657ed361d3ae67c7ca001cde623 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 25 Sep 2018 01:00:47 -0400 Subject: simplify alpha blending --- src/SMAPI/Framework/Content/AssetDataForImage.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/SMAPI/Framework/Content') diff --git a/src/SMAPI/Framework/Content/AssetDataForImage.cs b/src/SMAPI/Framework/Content/AssetDataForImage.cs index cd372948..a8ec79a8 100644 --- a/src/SMAPI/Framework/Content/AssetDataForImage.cs +++ b/src/SMAPI/Framework/Content/AssetDataForImage.cs @@ -84,13 +84,13 @@ namespace StardewModdingAPI.Framework.Content // merge pixels // This performs a conventional alpha blend for the pixels, which are already - // premultiplied by the content pipeline. - float alphaAbove = above.A / 255f; - float alphaBelow = (255 - above.A) / 255f; + // 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); newData[i] = new Color( - r: (int)((above.R * alphaAbove) + (below.R * alphaBelow)), - g: (int)((above.G * alphaAbove) + (below.G * alphaBelow)), - b: (int)((above.B * alphaAbove) + (below.B * alphaBelow)), + r: (int)(above.R + (below.R * alphaBelow)), + g: (int)(above.G + (below.G * alphaBelow)), + b: (int)(above.B + (below.B * alphaBelow)), a: Math.Max(above.A, below.A) ); } -- cgit From 5940f3283e7b06acae1873963d583f0d43487f94 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 9 Oct 2018 22:10:42 -0400 Subject: fix compile error on Linux/Mac --- src/SMAPI/Framework/Content/AssetDataForImage.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/SMAPI/Framework/Content') diff --git a/src/SMAPI/Framework/Content/AssetDataForImage.cs b/src/SMAPI/Framework/Content/AssetDataForImage.cs index a8ec79a8..f970762a 100644 --- a/src/SMAPI/Framework/Content/AssetDataForImage.cs +++ b/src/SMAPI/Framework/Content/AssetDataForImage.cs @@ -86,12 +86,14 @@ namespace StardewModdingAPI.Framework.Content // 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/. + // Note: don't use named arguments here since they're different between + // Linux/Mac and Windows. float alphaBelow = 1 - (above.A / 255f); newData[i] = new Color( - r: (int)(above.R + (below.R * alphaBelow)), - g: (int)(above.G + (below.G * alphaBelow)), - b: (int)(above.B + (below.B * alphaBelow)), - a: Math.Max(above.A, below.A) + (int)(above.R + (below.R * alphaBelow)), // r + (int)(above.G + (below.G * alphaBelow)), // g + (int)(above.B + (below.B * alphaBelow)), // b + Math.Max(above.A, below.A) // a ); } sourceData = newData; -- cgit