Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(Partial) Decoding png_xb1/bmp_xb1 Support #6

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions LibForge/LibForge/Texture/Texture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public class Mipmap
public int Width;
public int Height;
public int Flags;
public int DecompressedSize;
public int CompressionFlags;
public byte[] Data;
}
public int Version;
Expand Down
23 changes: 19 additions & 4 deletions LibForge/LibForge/Texture/TextureConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,19 @@ public static Bitmap ToBitmap(Texture t, int mipmap)
{
DecodeDXT(m, imageData, false);
}
else if (m.Data.Length >= imageData.Length)
{
// xb1 texture with mipmaps embedded
DecodeDXT(m, imageData, true, true);
}
else if (m.Data.Length >= (imageData.Length / 2))
{
// xb1 texture with mipmaps embedded
DecodeDXT(m, imageData, false, true);
}
else
{
throw new Exception($"Don't know what to do with this texture (version={t.Version})");
throw new Exception($"Don't know what to do with this texture (version={t.Version}, length={m.Data.Length}, imageLength={imageData.Length})");
}
// Copy data to bitmap
{
Expand All @@ -56,7 +66,7 @@ public static Bitmap ToBitmap(Texture t, int mipmap)
return output;
}

private static void DecodeDXT(Texture.Mipmap m, int[] imageData, bool DXT5)
private static void DecodeDXT(Texture.Mipmap m, int[] imageData, bool DXT5, bool xboxswizzle = false)
{
int[] colors = new int[4];
using (var s = new MemoryStream(m.Data))
Expand All @@ -66,7 +76,7 @@ private static void DecodeDXT(Texture.Mipmap m, int[] imageData, bool DXT5)
for (var y = 0; y < m.Height; y += 4)
for (var x = 0; x < m.Width; x += 4)
{
if (DXT5) s.Seek(8, SeekOrigin.Current);
if (DXT5) s.Seek(0x8, SeekOrigin.Current);
ushort c0 = s.ReadUInt16LE();
ushort c1 = s.ReadUInt16LE();
colors[0] = RGB565ToARGB(c0);
Expand Down Expand Up @@ -94,12 +104,17 @@ private static void DecodeDXT(Texture.Mipmap m, int[] imageData, bool DXT5)
colors[3] = Color.Black.ToArgb();
}
var offset = y * m.Width + x;
if (xboxswizzle)
{
// Xbox texture swizzling offset: https://github.com/Free60Project/libxenon/blob/master/libxenon/drivers/console/console.c#L60
offset = (((y >> 5) * 32 * m.Width + ((x >> 5) << 10) +(x & 3) + ((y & 1) << 2) + (((x & 31) >> 2) << 3) + (((y & 31) >> 1) << 6)) ^ ((y & 8) << 2)) / 4;
}
for (var i = 0; i < 4; i++)
{
for (var j = 0; j < 4; j++)
{
var idx = (iData[i] >> (2 * j)) & 0x3;
imageData[offset + i * m.Width + j] = colors[idx];
imageData[offset + (i * m.Width) + j] = colors[idx];
}
}
}
Expand Down
20 changes: 19 additions & 1 deletion LibForge/LibForge/Texture/TextureReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Text;
using System.IO;
using LibForge.Util;
using System.IO.Compression;

namespace LibForge.Texture
{
Expand All @@ -29,12 +30,29 @@ public override Texture Read()
{
Width = Int(),
Height = Int(),
Flags = version == 0xC ? Int().Then(Skip(8)) : Int()
Flags = Int(),
DecompressedSize = version == 0xC ? Int() : 0,
CompressionFlags = version == 0xC ? Int() : 0,
}, MipmapLevels);
UInt();
for(var i = 0; i < Mipmaps.Length; i++)
{
Mipmaps[i].Data = Arr(Byte);
// If there's a decompressed size we should zlib decompress the data
if (Mipmaps[i].DecompressedSize > 0)
{
byte[] decompressed = new byte[Mipmaps[i].DecompressedSize];
using (MemoryStream ms = new MemoryStream(Mipmaps[i].Data))
using (DeflateStream deflate = new DeflateStream(ms, CompressionMode.Decompress))
{
ms.Read(decompressed, 0, 2); // skip over zlib header
deflate.Read(decompressed, 0, Mipmaps[i].DecompressedSize);
}
Mipmaps[i].Data = decompressed;
}
// DDS textures (png_xb1/bmp_xb1) only have 1 blob of data for mipmaps
if (Mipmaps[i].CompressionFlags != 0)
break;
}
var footerData = FixedArr(Byte, 0x1C);
return new Texture
Expand Down