From 043508ed4264a3024b281665bfbf6e073c029fdf Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 3 Mar 2017 20:22:30 -0500 Subject: add texture patching to content events (#173) --- .../Framework/ContentEventHelper.cs | 51 ++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'src/StardewModdingAPI/Framework/ContentEventHelper.cs') diff --git a/src/StardewModdingAPI/Framework/ContentEventHelper.cs b/src/StardewModdingAPI/Framework/ContentEventHelper.cs index a58efe32..ebd04692 100644 --- a/src/StardewModdingAPI/Framework/ContentEventHelper.cs +++ b/src/StardewModdingAPI/Framework/ContentEventHelper.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace StardewModdingAPI.Framework @@ -85,6 +86,56 @@ namespace StardewModdingAPI.Framework data[key] = value(data[key]); } + /// Overwrite part of the image. + /// The image to patch into the content. + /// The part of the to copy (or null to take the whole texture). This must be within the bounds of the texture. + /// The part of the content to patch (or null to patch the whole texture). The original content within this area will be erased. This must be within the bounds of the existing spritesheet. + /// Indicates how an image should be patched. + /// One of the arguments is null. + /// The is outside the bounds of the spritesheet. + /// The content being read isn't an image. + public void PatchImage(Texture2D source, Rectangle? sourceArea = null, Rectangle? targetArea = null, PatchMode patchMode = PatchMode.Replace) + { + // get texture + Texture2D target = this.GetData(); + + // get areas + sourceArea = sourceArea ?? new Rectangle(0, 0, source.Width, source.Height); + targetArea = targetArea ?? new Rectangle(0, 0, Math.Min(sourceArea.Value.Width, target.Width), Math.Min(sourceArea.Value.Height, target.Height)); + + // validate + if (source == null) + throw new ArgumentNullException(nameof(source), "Can't patch from a null source texture."); + if (sourceArea.Value.X < 0 || sourceArea.Value.Y < 0 || sourceArea.Value.Right > source.Width || sourceArea.Value.Bottom > source.Height) + throw new ArgumentOutOfRangeException(nameof(sourceArea), "The source area is outside the bounds of the source texture."); + if (targetArea.Value.X < 0 || targetArea.Value.Y < 0 || targetArea.Value.Right > target.Width || targetArea.Value.Bottom > target.Height) + throw new ArgumentOutOfRangeException(nameof(targetArea), "The target area is outside the bounds of the target texture."); + if (sourceArea.Value.Width != targetArea.Value.Width || sourceArea.Value.Height != targetArea.Value.Height) + throw new InvalidOperationException("The source and target areas must be the same size."); + + // get source data + int pixelCount = sourceArea.Value.Width * sourceArea.Value.Height; + Color[] sourceData = new Color[pixelCount]; + source.GetData(0, sourceArea, sourceData, 0, pixelCount); + + // merge data in overlay mode + if (patchMode == PatchMode.Overlay) + { + 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 != 0) // not transparent + newData[i] = pixel; + } + sourceData = newData; + } + + // patch target texture + target.SetData(0, targetArea, sourceData, 0, pixelCount); + } + /// Replace the entire content value with the given value. This is generally not recommended, since it may break compatibility with other mods or different versions of the game. /// The new content value. /// The is null. -- cgit