Skip to content

Instantly share code, notes, and snippets.

@krzys-h
Created April 29, 2019 10:29
Show Gist options
  • Save krzys-h/81ee306d4b799972ed50c62b71d5c8cc to your computer and use it in GitHub Desktop.
Save krzys-h/81ee306d4b799972ed50c62b71d5c8cc to your computer and use it in GitHub Desktop.
UndertaleModLib overlay hitboxes on sprites
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using UndertaleModLib;
using UndertaleModLib.Models;
namespace SpriteOverlayer
{
class Program
{
static void Main(string[] args)
{
UndertaleData data = UndertaleIO.Read(new FileStream(@"C:\Users\krzys\Documents\Visual Studio 2017\Projects\UndertaleModTool\Test\bin\Debug\deltarune\triple.win", FileMode.Open));
Dictionary<UndertaleEmbeddedTexture, Image> modifiedTextures = new Dictionary<UndertaleEmbeddedTexture, Image>();
Dictionary<UndertaleEmbeddedTexture, Image> originalTextures = new Dictionary<UndertaleEmbeddedTexture, Image>();
foreach (var sprite in data.Sprites)
{
if (sprite.BBoxMode != 2)
continue;
Bitmap hitbox = new Bitmap((int)sprite.Width, (int)sprite.Height, PixelFormat.Format32bppArgb);
for (int y = 0; y < sprite.Height; ++y)
{
int row_start = (int)((sprite.Width + 7) / 8) * y;
for (int x = 0; x < sprite.Width; ++x)
{
int bytenum = row_start + x / 8;
int bitnum = x % 8;
hitbox.SetPixel(x, y, (sprite.CollisionMasks[0].Data[bytenum] & (1 << (7-bitnum))) != 0 ? Color.GreenYellow : Color.Transparent);
}
}
foreach(var frame in sprite.Textures)
{
if (frame.Texture.SourceWidth != frame.Texture.TargetWidth || frame.Texture.TargetWidth != frame.Texture.BoundingWidth || frame.Texture.SourceWidth != frame.Texture.BoundingWidth ||
frame.Texture.SourceHeight != frame.Texture.TargetHeight || frame.Texture.TargetHeight != frame.Texture.BoundingHeight || frame.Texture.SourceHeight != frame.Texture.BoundingHeight)
continue;
Debug.WriteLine(sprite.Name.Content + " " + sprite.Textures.IndexOf(frame));
if (!modifiedTextures.ContainsKey(frame.Texture.TexturePage))
{
using (var stream = new MemoryStream(frame.Texture.TexturePage.TextureData.TextureBlob))
{
originalTextures.Add(frame.Texture.TexturePage, Image.FromStream(stream));
modifiedTextures.Add(frame.Texture.TexturePage, Image.FromStream(stream));
}
}
Graphics g = Graphics.FromImage(modifiedTextures[frame.Texture.TexturePage]);
g.CompositingMode = CompositingMode.SourceCopy;
ImageAttributes transparent = new ImageAttributes();
ColorMatrix mat = new ColorMatrix();
mat.Matrix33 = 0.25f;
transparent.SetColorMatrix(mat, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
g.DrawImage(originalTextures[frame.Texture.TexturePage], new Rectangle(frame.Texture.SourceX, frame.Texture.SourceY, frame.Texture.SourceWidth, frame.Texture.SourceHeight), frame.Texture.SourceX, frame.Texture.SourceY, frame.Texture.SourceWidth, frame.Texture.SourceHeight, GraphicsUnit.Pixel, transparent);
g.CompositingMode = CompositingMode.SourceOver;
g.DrawImage(hitbox, frame.Texture.SourceX, frame.Texture.SourceY);
g.Dispose();
}
hitbox.Dispose();
}
foreach(var tex in modifiedTextures)
{
//tex.Value.Save("R:\\" + data.EmbeddedTextures.IndexOf(tex.Key) + ".png");
using (MemoryStream ms = new MemoryStream())
{
tex.Value.Save(ms, ImageFormat.Png);
tex.Key.TextureData.TextureBlob = ms.ToArray();
}
}
UndertaleIO.Write(new FileStream(@"C:\Users\krzys\Documents\Visual Studio 2017\Projects\UndertaleModTool\Test\bin\Debug\deltarune\triple_masked.win", FileMode.Create), data);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment