Skip to content

Commit

Permalink
actually working SprPainter #124
Browse files Browse the repository at this point in the history
  • Loading branch information
UlyssesWu committed Sep 25, 2024
1 parent 43ea3a5 commit 6f625c0
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 37 deletions.
149 changes: 115 additions & 34 deletions FreeMote.Psb/SprPainter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.IO;
using FreeMote.Psb.Types;
using FastBitmapLib;
using System.Drawing.Imaging;

namespace FreeMote.Psb
{
Expand All @@ -21,11 +22,15 @@ public class SprPainter
private readonly Dictionary<int, Bitmap> _textures = new Dictionary<int, Bitmap>();

//palette: each single line is a palette
public Bitmap Palette { get; set; }

public SprPainter(PSB sprData, string basePath)
public string PaletteName { get; set; }

public SprPainter(PSB sprData, string basePath, string paletteName = "1ppalette")
{
SprData = sprData;
BasePath = basePath;
PaletteName = paletteName;
}

private void Collect()
Expand All @@ -34,6 +39,7 @@ private void Collect()
{
//read images from BasePath\__ddd.psb.m\*.png
var dirs = Directory.GetDirectories(BasePath, "*.psb.m", SearchOption.TopDirectoryOnly);
string prefix = string.Empty;
foreach (var dir in dirs)
{
var png = Path.Combine(dir, "0.png");
Expand All @@ -42,9 +48,14 @@ private void Collect()
var dirName = Path.GetFileName(dir);
try
{
if(int.TryParse(dirName.Substring(dirName.IndexOf('.') - IdWidth, IdWidth), out int number))
if (int.TryParse(dirName.Substring(dirName.IndexOf('.') - IdWidth, IdWidth), out int number))
{
_textures.Add(number, new Bitmap(png));
if (string.IsNullOrEmpty(prefix))
{
prefix = dirName.Substring(0, dirName.IndexOf('.') - IdWidth);
}

_textures.Add(number, BitmapHelper.LoadBitmap(File.ReadAllBytes(png)));
}
}
catch (Exception ex)
Expand All @@ -53,6 +64,25 @@ private void Collect()
}
}
}

var paletteDir = Path.Combine(BasePath, PaletteName + ".psb.m");
if (Directory.Exists(paletteDir))
{
Palette = new Bitmap(Path.Combine(paletteDir, "0.png"));
}
else if (!string.IsNullOrEmpty(prefix))
{
paletteDir = Path.Combine(BasePath, prefix + PaletteName + ".psb.m");
if (Directory.Exists(paletteDir) && File.Exists(Path.Combine(paletteDir, "0.png")))
{
Palette = new Bitmap(Path.Combine(paletteDir, "0.png"));
}
}
else
{
Logger.LogError($"Cannot find palette {PaletteName} in {BasePath}. Will not apply palette.");
Palette = null;
}
}
else
{
Expand Down Expand Up @@ -100,7 +130,22 @@ public Dictionary<string, Bitmap> Draw()
var org = sprImage.Children("org") as PsbList;
var width = org[0].GetInt();
var height = org[1].GetInt();
var bitmap = new Bitmap(width, height);
Bitmap bitmap;
try
{
bitmap = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
var palette = sprImage.Children("palette").GetInt();
ColorPalette pal = bitmap.Palette;
for (int c = 0; c < 256; c++)
pal.Entries[c] = Palette == null? Color.FromArgb(c, c, c, 0xFF) : Palette.GetPixel(c, palette);
bitmap.Palette = pal;
}
catch (Exception ex)
{
Logger.LogError($"Error creating palette indexed bitmap: {ex.Message}");
return result;
}

var tiles = new List<SprTile>();
PsbList data = sprImage.Children("data") as PsbList;
foreach (var tileData in data)
Expand All @@ -116,40 +161,76 @@ public Dictionary<string, Bitmap> Draw()
tiles.Add(tile);
}

using (var f = bitmap.FastLock())
foreach (var tile in tiles)
{
foreach (var tile in tiles)
var texId = tile.TexId;
if (!_textures.ContainsKey(texId))
{
var texId = tile.TexId;
if (!_textures.ContainsKey(texId))
{
Logger.LogError($"Tex missing: {texId} required by: {tile}");
continue;
}
var tex = _textures[texId];

var texWidth = tex.Width;
var texHeight = tex.Height; //useless, the ID is only related to width
var tilePerLine = texWidth / TileWidth;

// 0 1 2 3 ... 31
// ...
// 31*32 31*32+1 31*32+2 ... 31*32+31
//calculate source rect from tile.Id
var sourceRect = new Rectangle(
(tile.Id % tilePerLine) * TileWidth,
(tile.Id / tilePerLine) * TileHeight,
TileWidth,
TileHeight
);
var tileX = tile.X;
var tileY = tile.Y;

f.CopyRegion(tex, sourceRect, new Rectangle(tileX * TileWidth, tileY * TileHeight, TileWidth, TileHeight));
Logger.LogError($"Tex missing: {texId} required by: {tile}");
continue;
}

result.Add(i.ToString(), bitmap);
var tex = _textures[texId];
tex.Palette = bitmap.Palette;

var texWidth = tex.Width;
var texHeight = tex.Height; //useless, the ID is only related to width
var tilePerLine = texWidth / TileWidth;

// 0 1 2 3 ... 31
// ...
// 31*32 31*32+1 31*32+2 ... 31*32+31
//calculate source rect from tile.Id
var sourceRect = new Rectangle(
(tile.Id % tilePerLine) * TileWidth,
(tile.Id / tilePerLine) * TileHeight,
TileWidth,
TileHeight
);
var tileX = tile.X;
var tileY = tile.Y;

bitmap.CopyRegion(tex, sourceRect, new Rectangle(tileX * TileWidth, tileY * TileHeight, TileWidth, TileHeight));
}
result.Add(i.ToString(), bitmap);


// RGBA8
// {
// using (var f = bitmap.FastLock())
// {
// foreach (var tile in tiles)
// {
// var texId = tile.TexId;
// if (!_textures.ContainsKey(texId))
// {
// Logger.LogError($"Tex missing: {texId} required by: {tile}");
// continue;
// }
// var tex = _textures[texId];

// var texWidth = tex.Width;
// var texHeight = tex.Height; //useless, the ID is only related to width
// var tilePerLine = texWidth / TileWidth;

// // 0 1 2 3 ... 31
// // ...
// // 31*32 31*32+1 31*32+2 ... 31*32+31
// //calculate source rect from tile.Id
// var sourceRect = new Rectangle(
// (tile.Id % tilePerLine) * TileWidth,
// (tile.Id / tilePerLine) * TileHeight,
// TileWidth,
// TileHeight
// );
// var tileX = tile.X;
// var tileY = tile.Y;

// f.CopyRegion(tex, sourceRect, new Rectangle(tileX * TileWidth, tileY * TileHeight, TileWidth, TileHeight));
// }
// }
// result.Add(i.ToString(), bitmap);
// }

}

return result;
Expand Down
15 changes: 13 additions & 2 deletions FreeMote.Psb/Types/M2Types.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,20 @@ ImageMetadata GenerateMetadata(string name, PsbDictionary dic, PsbResource res)
var dataLen = res.Data.Length;
var depth = dataLen / (width * height);
PsbPixelFormat format = PsbPixelFormat.A8;
byte[] palette = null;
switch (depth)
{
case 1:
format = PsbPixelFormat.A8;
format = PsbPixelFormat.CI8;
palette = new byte[256 * 4];
// fill with 256 degrees of gray
for (int i = 0; i < 256; i++)
{
palette[i * 4] = (byte)i;
palette[i * 4 + 1] = (byte)i;
palette[i * 4 + 2] = (byte)i;
palette[i * 4 + 3] = 0xFF;
}
break;
case 4:
format = PsbPixelFormat.LeRGBA8;
Expand All @@ -80,7 +90,8 @@ ImageMetadata GenerateMetadata(string name, PsbDictionary dic, PsbResource res)
Width = width,
Height = height,
Spec = PsbSpec.none,
TypeString = format.ToStringForPsb().ToPsbString()
TypeString = format.ToStringForPsb().ToPsbString(),
Palette = new PsbResource(){Data = palette},
};

return md;
Expand Down
38 changes: 37 additions & 1 deletion FreeMote/BitmapExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,43 @@ public static class BitmapExtension
/// <exception cref="ArgumentException">The provided source bitmap is the same bitmap locked in this FastBitmap</exception>
public static void CopyRegion(this Bitmap target, Bitmap source, Rectangle srcRect, Rectangle destRect)
{
//TODO:
if (srcRect.Width != destRect.Width || srcRect.Height != destRect.Height)
{
throw new ArgumentException("Source and destination rectangles must have the same dimensions.");
}

var srcData = source.LockBits(srcRect, ImageLockMode.ReadOnly, source.PixelFormat);
var destData = target.LockBits(destRect, ImageLockMode.WriteOnly, target.PixelFormat);

try
{
unsafe
{
byte* srcPtr = (byte*)srcData.Scan0;
byte* destPtr = (byte*)destData.Scan0;

int bytesPerPixel = Image.GetPixelFormatSize(source.PixelFormat) / 8;
int stride = srcData.Stride;
int height = srcRect.Height;
int widthInBytes = srcRect.Width * bytesPerPixel;

for (int y = 0; y < height; y++)
{
byte* srcRow = srcPtr + (y * stride);
byte* destRow = destPtr + (y * destData.Stride);

for (int x = 0; x < widthInBytes; x++)
{
destRow[x] = srcRow[x];
}
}
}
}
finally
{
source.UnlockBits(srcData);
target.UnlockBits(destData);
}
}

/// <summary>
Expand Down

0 comments on commit 6f625c0

Please sign in to comment.