add support for semi-transparency when overlaying images

This commit is contained in:
Jesse Plamondon-Willard 2018-09-25 00:58:46 -04:00
parent 99e4a4a1cc
commit b9844c4acd
2 changed files with 37 additions and 3 deletions

View File

@ -19,6 +19,7 @@
* For modders:
* Added [data API](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Data).
* Added support for overlaying images with semi-transparency using `asset.AsImage().PatchImage`.
* Added `IContentPack.WriteJsonFile` method.
* Added IntelliSense documentation when not using the 'for developers' version of SMAPI.
* Mods are no longer prevented from loading a PNG while the game is drawing.

View File

@ -7,6 +7,14 @@ namespace StardewModdingAPI.Framework.Content
/// <summary>Encapsulates access and changes to image content being read from a data file.</summary>
internal class AssetDataForImage : AssetData<Texture2D>, IAssetDataForImage
{
/*********
** Properties
*********/
/// <summary>The minimum value to consider non-transparent.</summary>
/// <remarks>On Linux/Mac, fully transparent pixels may have an alpha up to 4 for some reason.</remarks>
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;
}