private void ExtractFrames(Texture2D spriteSheet, int frameWidth, int frameHeight) { List <Texture2D> frames = new List <Texture2D>(); int pixelCountPerFrame = frameWidth * frameHeight; bool foundEmptyFrame = false; for (int y = 0; y < spriteSheet.Height; y += frameHeight) { if (y + frameHeight <= spriteSheet.Height && !foundEmptyFrame) { for (int x = 0; x < spriteSheet.Width; x += frameWidth) { if (x + frameWidth <= spriteSheet.Width && !foundEmptyFrame) { var frameData = new Color[pixelCountPerFrame]; spriteSheet.GetData(0, new Rectangle(x, y, frameWidth, frameHeight), frameData, 0, pixelCountPerFrame); if (frameData.All(c => c.A == 0)) { foundEmptyFrame = true; } else { Texture2D frame = new Texture2D(GameProvider.GameInstance.GraphicsDevice, frameWidth, frameHeight); frame.SetData(frameData); frames.Add(frame); } } } } } _frames = frames.ToArray(); }
public void Edit <T>(IAssetData asset) { const int styleW = 16; const int styleH = 128; // Dictionary data var data = asset.AsDictionary <int, string>().Data; var newData = new Dictionary <int, string>(); // Image data Texture2D hairstylesTexture = Game1.content.Load <Texture2D> (ModConsts.GameContentHairstyleImagePath); int count = 0; Color[] pixelData = new Color[styleW * styleH]; // Find index of first non-empty slot in custom hairstyles spritesheet for (int x = (hairstylesTexture.Width / styleW) - 1; x >= 0 && count == 0; --x) { for (int y = (hairstylesTexture.Height / styleH) - 1; y >= 0 && count == 0; --y) { int cur = x + (hairstylesTexture.Width / styleW * y); hairstylesTexture.GetData(0, new Rectangle(x * styleW, y * styleH, styleW, styleH), pixelData, 0, pixelData.Length); if (!pixelData.All(colour => colour.A == 0)) { count = cur + 1; } } } Log.D($"Hairstyles to add: {count}", ModEntry.Config.DebugMode); // Add in HairData entries for every hairstyle up until the last non-empty hairstyle in the spritesheet const bool hasLeftStyle = true; const bool isBaldStyle = false; const int coveredStyleId = -1; int startId = int.Parse(ModEntry.Instance.ModManifest.UpdateKeys.First().Split(':')[1]) * 100; if (data.Keys.Count(key => key >= startId && key < startId + count) is int conflicts && conflicts > 0) { Log.W($"Identified ID conflicts with {conflicts} hairstyles: Please share a log file on the mod page!"); } for (int i = 0; i < count; ++i) { int styleId = startId + i; if (data.ContainsKey(styleId)) { string[] style = data[styleId].Split('/'); Log.W($"Overriding hairstyle at {styleId} ({style[0]} at X:{style[1]}, Y:{style[2]})"); } int x = i % 8; int y = (int)(i * 0.125) * 8; newData.Add(styleId, $"{ModConsts.HairstylesSheetId}/{x}/{y}/{hasLeftStyle}/{coveredStyleId}/{isBaldStyle}"); } Log.D(newData.Aggregate("HairData:", (total, cur) => $"{total}\n{cur.Key}: {cur.Value}"), ModEntry.Config.DebugMode); asset.ReplaceWith(data.Concat(newData).ToDictionary(pair => pair.Key, pair => pair.Value)); }
/// <summary> /// Draws the elements border to the window. Skips sides that have color set to <see cref="Color.Transparent"/> /// </summary> /// <param name="spriteBatch">Sprite batch to draw the border to.</param> protected void DrawBorder(SpriteBatch spriteBatch) { var colors = new Color[] { BorderTopColor, BorderRightColor, BorderBottomColor, BorderLeftColor }; if (colors.All(clr => clr == BorderTopColor)) { spriteBatch.DrawRectangle(_borderRect, BorderTopColor, BorderWidth); } else { if (BorderTopColor != Color.Transparent) { spriteBatch.DrawLine(_borderTop.Start, _borderTop.End, BorderTopColor, BorderWidth); } if (BorderRightColor != Color.Transparent) { spriteBatch.DrawLine(_borderRight.Start, _borderRight.End, BorderRightColor, BorderWidth); } if (BorderBottomColor != Color.Transparent) { spriteBatch.DrawLine(_borderBottom.Start, _borderBottom.End, BorderBottomColor, BorderWidth); } if (BorderLeftColor != Color.Transparent) { spriteBatch.DrawLine(_borderLeft.Start, _borderLeft.End, BorderLeftColor, BorderWidth); } } }
private bool IsRegionTransparent(Texture2D texture, Rectangle r) { int size = r.Width * r.Height; Color[] buffer = new Color[size]; texture.GetData(0, r, buffer, 0, size); return(buffer.All(c => c == Color.Transparent)); }
private int GetTopPixel() { var data = _enfFileProvider.ENFFile[NPC.ID]; var frameTexture = _npcSpriteSheet.GetNPCTexture(data.Graphic, NPCFrame.Standing, EODirection.Down); var frameTextureData = new Color[frameTexture.Width * frameTexture.Height]; frameTexture.GetData(frameTextureData); if (frameTextureData.All(x => x.A == 0)) { return(0); } var firstVisiblePixelIndex = frameTextureData.Select((color, index) => new { color, index }) .Where(x => x.color.A != 0) .Select(x => x.index) .First(); return(firstVisiblePixelIndex / frameTexture.Height); }
private void InitializeTopPixel() { int tries; for (tries = 0; tries < 3; ++tries) { try { //get the first non-transparent pixel to determine offsets for name labels and damage counters var frameTexture = _npcSheet.GetNPCTexture(NPC.Data.Graphic, NPCFrame.Standing, NPC.Direction); var frameTextureData = new Color[frameTexture.Width * frameTexture.Height]; frameTexture.GetData(frameTextureData); if (frameTextureData.All(x => x.A == 0)) { TopPixel = 0; } else { var firstVisiblePixelIndex = frameTextureData.Select((color, index) => new { color, index }) .Where(x => x.color.R != 0) .Select(x => x.index) .First(); TopPixel = firstVisiblePixelIndex / frameTexture.Height; } } //this block throws errors sometimes..no idea why. It usually doesn't fail 3 times. catch (InvalidOperationException) { continue; } break; } if (tries >= 3) { throw new InvalidOperationException("Something weird happened initializing this NPC."); } }
public static void Main(string[] args) { Console.WriteLine("Enter input path: "); string image = Console.ReadLine(); Console.WriteLine("Enter settings of conversion to black (semicolon-separated rules): "); Console.WriteLine("For R: "); string rRule = Console.ReadLine(); ColorCondition[] rPredicates = ParseRule(rRule, color => color.R); Console.WriteLine("For G: "); string gRule = Console.ReadLine(); ColorCondition[] gPredicates = ParseRule(gRule, color => color.G); Console.WriteLine("For B: "); string bRule = Console.ReadLine(); ColorCondition[] bPredicates = ParseRule(bRule, color => color.B); if (rPredicates.Length != gPredicates.Length || rPredicates.Length != bPredicates.Length) { throw new Exception(); } Predicate <Color>[] strictShouldBeBlack = Enumerable.Range(0, rPredicates.Length) .Where(i => rPredicates[i].IsStrict) .Select(i => new Predicate <Color>(color => rPredicates[i].Predicate(color) && gPredicates[i].Predicate(color) && bPredicates[i].Predicate(color))) .ToArray(); Predicate <Color>[] shouldBeBlack = Enumerable.Range(0, rPredicates.Length) .Where(i => !rPredicates[i].IsStrict) .Select(i => new Predicate <Color>(color => rPredicates[i].Predicate(color) && gPredicates[i].Predicate(color) && bPredicates[i].Predicate(color))) .ToArray(); using (Bitmap bmp = new Bitmap(image)) { for (int i = 0; i < bmp.Height; ++i) { for (int j = 0; j < bmp.Width; ++j) { Color pixel = bmp.GetPixel(j, i); if (pixel.R == 53 && pixel.G == 61 && pixel.B == 213) { for (int k = 0; k <= 14 && i + k < bmp.Height; ++k) { for (int q = 0; q <= 14 && j + q < bmp.Width; ++q) { bmp.SetPixel(j + q, i + k, Color.White); } } } if (pixel.R == 244 && pixel.G == 223 && pixel.B == 116) { for (int k = 0; k <= 10 && i + k < bmp.Height; ++k) { for (int q = -2; q <= 3 && j + q < bmp.Width; ++q) { Color currentPixel = bmp.GetPixel(j + q, i + k); bmp.SetPixel(j + q, i + k, currentPixel.R > 200 && currentPixel.G > 200 && currentPixel.B > 200 ? Color.White : Color.Black); } } } if (pixel.R == 102 && pixel.G == 102 && pixel.B == 102) { Color[] testPixels = new Color[] { bmp.GetPixel(j + 1, i + 1), bmp.GetPixel(j + 2, i + 2) }; if (testPixels.All(testPixel => testPixel.R == 102 && testPixel.G == 102 && testPixel.B == 102)) { for (int k = -2; k < 8 && i + k < bmp.Height; ++k) { for (int q = -2; q < 8 && j + q < bmp.Width; ++q) { bmp.SetPixel(j + q, i + k, Color.White); } } } } bmp.SetPixel(j, i, strictShouldBeBlack.All(pred => pred(pixel)) && shouldBeBlack.Any(pred => pred(pixel)) ? Color.Black : Color.White); } } int indexOfExtension = image.LastIndexOf('.'); string name = image.Substring(0, indexOfExtension); string extension = image.Substring(indexOfExtension); if (File.Exists(name + "-modified" + extension)) { int i = 0; for (; File.Exists(name + "-modified-" + i + extension); ++i) { ; } bmp.Save(name + "-modified-" + i + extension); } else { bmp.Save(name + "-modified" + extension); } } }
private void InitializeTopPixel() { int tries; for (tries = 0; tries < 3; ++tries) { try { //get the first non-transparent pixel to determine offsets for name labels and damage counters Frame = NPCFrame.Standing; var frameTexture = _npcSheet.GetNPCTexture(); var frameTextureData = new Color[frameTexture.Width * frameTexture.Height]; frameTexture.GetData(frameTextureData); if (frameTextureData.All(x => x.A == 0)) TopPixel = 0; else { var firstVisiblePixelIndex = frameTextureData.Select((color, index) => new { color, index }) .Where(x => x.color.R != 0) .Select(x => x.index) .First(); TopPixel = firstVisiblePixelIndex/frameTexture.Height; } } //this block throws errors sometimes..no idea why. It usually doesn't fail 3 times. catch (InvalidOperationException) { continue; } break; } if (tries >= 3) throw new InvalidOperationException("Something weird happened initializing this NPC."); }