mirror of
https://github.com/aelurum/AssetStudio.git
synced 2026-11-14 11:18:47 -05:00
Update cropping method for Switch deswizzler
Inspired by AssetRipper, yeah
This commit is contained in:
@@ -10,8 +10,6 @@ namespace AssetStudio
|
||||
private ResourceReader reader;
|
||||
private int m_Width;
|
||||
private int m_Height;
|
||||
private int m_WidthCrop;
|
||||
private int m_HeightCrop;
|
||||
private TextureFormat m_TextureFormat;
|
||||
private byte[] m_PlatformBlob;
|
||||
private UnityVersion version;
|
||||
@@ -23,13 +21,12 @@ namespace AssetStudio
|
||||
private SixLabors.ImageSharp.Size blockSize;
|
||||
|
||||
public int OutputDataSize => outPutDataSize;
|
||||
public bool UsesSwitchSwizzle => switchSwizzled;
|
||||
|
||||
public Texture2DConverter(Texture2D m_Texture2D)
|
||||
{
|
||||
reader = m_Texture2D.image_data;
|
||||
m_WidthCrop = m_Texture2D.m_Width;
|
||||
m_HeightCrop = m_Texture2D.m_Height;
|
||||
m_Width = m_Texture2D.m_Width;
|
||||
m_Height = m_Texture2D.m_Height;
|
||||
m_TextureFormat = m_Texture2D.m_TextureFormat;
|
||||
m_PlatformBlob = m_Texture2D.m_PlatformBlob;
|
||||
version = m_Texture2D.version;
|
||||
@@ -42,11 +39,6 @@ namespace AssetStudio
|
||||
{
|
||||
SetupSwitchSwizzle();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Width = m_WidthCrop;
|
||||
m_Height = m_HeightCrop;
|
||||
}
|
||||
outPutDataSize = m_Width * m_Height * 4;
|
||||
}
|
||||
|
||||
@@ -57,27 +49,20 @@ namespace AssetStudio
|
||||
//work fine for now
|
||||
gobsPerBlock = 1 << BitConverter.ToInt32(m_PlatformBlob, 8);
|
||||
|
||||
//in older versions of unity, rgb24 has a platformBlob which shouldn't
|
||||
//be possible. it turns out in this case, the image is just rgba32.
|
||||
//probably shouldn't be modifying the texture2d here, but eh, who cares
|
||||
if (m_TextureFormat == TextureFormat.RGB24)
|
||||
switch (m_TextureFormat)
|
||||
{
|
||||
m_TextureFormat = TextureFormat.RGBA32;
|
||||
}
|
||||
else if (m_TextureFormat == TextureFormat.BGR24)
|
||||
{
|
||||
m_TextureFormat = TextureFormat.BGRA32;
|
||||
//in older versions of unity, rgb24 has a platformBlob which shouldn't
|
||||
//be possible. it turns out in this case, the image is just rgba32.
|
||||
//probably shouldn't be modifying the texture2d here, but eh, who cares
|
||||
case TextureFormat.RGB24:
|
||||
m_TextureFormat = TextureFormat.RGBA32;
|
||||
break;
|
||||
case TextureFormat.BGR24:
|
||||
m_TextureFormat = TextureFormat.BGRA32;
|
||||
break;
|
||||
}
|
||||
|
||||
blockSize = Texture2DSwitchDeswizzler.GetTextureFormatBlockSize(m_TextureFormat);
|
||||
var realSize = Texture2DSwitchDeswizzler.GetPaddedTextureSize(m_WidthCrop, m_HeightCrop, blockSize.Width, blockSize.Height, gobsPerBlock);
|
||||
m_Width = realSize.Width;
|
||||
m_Height = realSize.Height;
|
||||
}
|
||||
|
||||
public SixLabors.ImageSharp.Size GetUncroppedSize()
|
||||
{
|
||||
return new SixLabors.ImageSharp.Size(m_Width, m_Height);
|
||||
}
|
||||
|
||||
public bool DecodeTexture2D(byte[] bytes)
|
||||
@@ -93,18 +78,9 @@ namespace AssetStudio
|
||||
_ = reader.GetData(buff);
|
||||
if (switchSwizzled)
|
||||
{
|
||||
var unswizzledData = BigArrayPool<byte>.Shared.Rent(reader.Size);
|
||||
try
|
||||
{
|
||||
Texture2DSwitchDeswizzler.Unswizzle(buff, GetUncroppedSize(), blockSize, gobsPerBlock, unswizzledData);
|
||||
BigArrayPool<byte>.Shared.Return(buff, clearArray: true);
|
||||
buff = unswizzledData;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BigArrayPool<byte>.Shared.Return(unswizzledData, clearArray: true);
|
||||
Logger.Error(e.Message, e);
|
||||
}
|
||||
var spanBuff = buff.AsSpan(0, reader.Size);
|
||||
var textureSize = new SixLabors.ImageSharp.Size(m_Width, m_Height);
|
||||
Texture2DSwitchDeswizzler.Unswizzle(ref spanBuff, textureSize, blockSize, gobsPerBlock);
|
||||
}
|
||||
|
||||
switch (m_TextureFormat)
|
||||
|
||||
@@ -18,17 +18,7 @@ namespace AssetStudio
|
||||
if (!converter.DecodeTexture2D(buff))
|
||||
return null;
|
||||
|
||||
Image<Bgra32> image;
|
||||
if (converter.UsesSwitchSwizzle)
|
||||
{
|
||||
var uncroppedSize = converter.GetUncroppedSize();
|
||||
image = Image.LoadPixelData<Bgra32>(spanBuff, uncroppedSize.Width, uncroppedSize.Height);
|
||||
image.Mutate(x => x.Crop(m_Texture2D.m_Width, m_Texture2D.m_Height));
|
||||
}
|
||||
else
|
||||
{
|
||||
image = Image.LoadPixelData<Bgra32>(spanBuff, m_Texture2D.m_Width, m_Texture2D.m_Height);
|
||||
}
|
||||
var image = Image.LoadPixelData<Bgra32>(spanBuff, m_Texture2D.m_Width, m_Texture2D.m_Height);
|
||||
|
||||
if (flip)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// https://github.com/nesrak1/AssetStudio/tree/switch-tex-deswizzle
|
||||
//src: https://github.com/nesrak1/AssetStudio/tree/switch-tex-deswizzle
|
||||
|
||||
using SixLabors.ImageSharp;
|
||||
using System;
|
||||
@@ -38,43 +38,66 @@ namespace AssetStudio
|
||||
NPRTVX...
|
||||
*/
|
||||
|
||||
private static int CeilDivide(int a, int b)
|
||||
internal static void Unswizzle(ref Span<byte> data, Size textureSize, Size blockSize, int gobsPerBlock)
|
||||
{
|
||||
return (a + b - 1) / b;
|
||||
}
|
||||
var paddedSize = GetPaddedTextureSize(textureSize, blockSize, gobsPerBlock);
|
||||
|
||||
internal static void Unswizzle(ReadOnlySpan<byte> data, Size imageSize, Size blockSize, int gobsPerBlock, Span<byte> newData)
|
||||
{
|
||||
int width = imageSize.Width;
|
||||
int height = imageSize.Height;
|
||||
|
||||
int blockCountX = CeilDivide(width, blockSize.Width);
|
||||
int blockCountY = CeilDivide(height, blockSize.Height);
|
||||
int blockCountX = CeilDivide(paddedSize.Width, blockSize.Width);
|
||||
int blockCountY = CeilDivide(paddedSize.Height, blockSize.Height);
|
||||
|
||||
int gobCountX = blockCountX / GOB_X_TEXEL_COUNT;
|
||||
int gobCountY = blockCountY / GOB_Y_TEXEL_COUNT;
|
||||
|
||||
int srcPos = 0;
|
||||
for (int i = 0; i < gobCountY / gobsPerBlock; i++)
|
||||
var unswizzledData = BigArrayPool<byte>.Shared.Rent(data.Length);
|
||||
var unswizzledDataSpan = unswizzledData.AsSpan(0, data.Length);
|
||||
try
|
||||
{
|
||||
for (int j = 0; j < gobCountX; j++)
|
||||
int srcPos = 0;
|
||||
for (int i = 0; i < gobCountY / gobsPerBlock; i++)
|
||||
{
|
||||
for (int k = 0; k < gobsPerBlock; k++)
|
||||
for (int j = 0; j < gobCountX; j++)
|
||||
{
|
||||
for (int l = 0; l < BLOCKS_IN_GOB; l++)
|
||||
for (int k = 0; k < gobsPerBlock; k++)
|
||||
{
|
||||
int gobX = GOB_X_POSES[l];
|
||||
int gobY = GOB_Y_POSES[l];
|
||||
int gobDstX = j * GOB_X_TEXEL_COUNT + gobX;
|
||||
int gobDstY = (i * gobsPerBlock + k) * GOB_Y_TEXEL_COUNT + gobY;
|
||||
int gobDstLinPos = gobDstY * blockCountX * TEXEL_BYTE_SIZE + gobDstX * TEXEL_BYTE_SIZE;
|
||||
for (int l = 0; l < BLOCKS_IN_GOB; l++)
|
||||
{
|
||||
int gobX = GOB_X_POSES[l];
|
||||
int gobY = GOB_Y_POSES[l];
|
||||
int gobDstX = j * GOB_X_TEXEL_COUNT + gobX;
|
||||
int gobDstY = (i * gobsPerBlock + k) * GOB_Y_TEXEL_COUNT + gobY;
|
||||
int gobDstLinPos = gobDstY * blockCountX * TEXEL_BYTE_SIZE + gobDstX * TEXEL_BYTE_SIZE;
|
||||
|
||||
data.Slice(srcPos, TEXEL_BYTE_SIZE).CopyTo(newData.Slice(gobDstLinPos));
|
||||
data.Slice(srcPos, TEXEL_BYTE_SIZE).CopyTo(unswizzledDataSpan.Slice(gobDstLinPos));
|
||||
|
||||
srcPos += TEXEL_BYTE_SIZE;
|
||||
srcPos += TEXEL_BYTE_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Crop unswizzled image if needed
|
||||
var blockByteSize = TEXEL_BYTE_SIZE / (blockSize.Width / blockSize.Height);
|
||||
var blocksPerTexel = TEXEL_BYTE_SIZE / blockByteSize;
|
||||
var paddedTexBlockCountX = CeilDivide(paddedSize.Width * blocksPerTexel, blockSize.Width);
|
||||
var texBlockCountX = CeilDivide(textureSize.Width * blocksPerTexel, blockSize.Width);
|
||||
if (paddedTexBlockCountX - texBlockCountX > 0)
|
||||
{
|
||||
var texBlockCountY = CeilDivide(textureSize.Height, blockSize.Height);
|
||||
for (var y = 0; y < texBlockCountY; y++)
|
||||
{
|
||||
unswizzledDataSpan.Slice(y * paddedTexBlockCountX * blockByteSize, texBlockCountX * blockByteSize).CopyTo(unswizzledDataSpan.Slice(y * texBlockCountX * blockByteSize));
|
||||
}
|
||||
unswizzledDataSpan.Slice(texBlockCountY * texBlockCountX * blockByteSize).Clear();
|
||||
}
|
||||
unswizzledDataSpan.CopyTo(data);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Warning($"Failed to deswizzle the image.\n{e}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
BigArrayPool<byte>.Shared.Return(unswizzledData, clearArray: true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,11 +140,16 @@ namespace AssetStudio
|
||||
};
|
||||
}
|
||||
|
||||
internal static Size GetPaddedTextureSize(int width, int height, int blockWidth, int blockHeight, int gobsPerBlock)
|
||||
private static Size GetPaddedTextureSize(Size textureSize, Size blockSize, int gobsPerBlock)
|
||||
{
|
||||
width = CeilDivide(width, blockWidth * GOB_X_TEXEL_COUNT) * blockWidth * GOB_X_TEXEL_COUNT;
|
||||
height = CeilDivide(height, blockHeight * GOB_Y_TEXEL_COUNT * gobsPerBlock) * blockHeight * GOB_Y_TEXEL_COUNT * gobsPerBlock;
|
||||
var width = CeilDivide(textureSize.Width, blockSize.Width * GOB_X_TEXEL_COUNT) * blockSize.Width * GOB_X_TEXEL_COUNT;
|
||||
var height = CeilDivide(textureSize.Height, blockSize.Height * GOB_Y_TEXEL_COUNT * gobsPerBlock) * blockSize.Height * GOB_Y_TEXEL_COUNT * gobsPerBlock;
|
||||
return new Size(width, height);
|
||||
}
|
||||
|
||||
private static int CeilDivide(int a, int b)
|
||||
{
|
||||
return (a + b - 1) / b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user